Как дождаться добавления ключа в коллекцию

#c# #.net #multithreading #thread-safety

#c# #.net #многопоточность #безопасность потоков

Вопрос:

Я хотел бы найти чистый способ для потока подождать, пока ключ не будет найден в коллекции (точно зная, что это произойдет в какой-то момент)

Для некоторого контекста у меня есть список элементов, которые необходимо проверить. Словарь будет содержать идентификатор элемента в качестве ключа и bool в качестве значения. Однако эти элементы не находятся в плоском списке. Элемент связан как следующий после предыдущего элемента (многие ко многим). За элементом может следовать и / или предшествовать несколько элементов. Также может быть несколько начальных точек. Однако циклов нет.

Элемент будет проверен только в том случае, если все его предыдущие элементы также будут проверены. Из-за отношения «многие ко многим» между элементами очень возможно, что элемент будет проверен дважды. Вот почему я создаю новый список, содержащий только все элементы, которые проверены или проверяются (позже они будут называться просмотренными элементами).

Пример :

    Item1 -- > Item3 --> Item4 -- > Item6
          /                    /
   Item2 /  ----------> Item5 /
  

Я начинаю с item6, добавляю его к просмотренным элементам, затем параллельно проверяю все предыдущие элементы (4,5). Затем Item5 проверит item2. Затем Item4 проверит 3, 2 и 1. Теперь Item2 будет проверен дважды.
Чтобы противостоять этому, поток сначала проверит, есть ли item2 уже в просмотренных элементах, и если да, получит значение из словаря результатов вместо повторной проверки.

Проблема:

Когда поток, которому необходимо проверить item2, находит item2 в просмотренных элементах, он еще не знает значения. Возможно, значение еще не вычислено, потому что другой поток все еще занят, проверил его. Как бы я приказал этому потоку дождаться добавления этого элемента в результирующий словарь и после его добавления получить его значение и продолжить работу в обычном режиме? (Я точно знаю, что в какой-то момент он будет добавлен)

(Далее немного не 100% понимания многопоточности)
Конечно, было бы неплохо, если бы поток, который застрял в ожидании, можно было бы использовать где-нибудь еще для проверки элементов, которые еще не проверяются, если это имеет смысл.

Код:

 // Item not yet checked
if (alreadySeenActions.TryAdd(item.Id, item.Id))
{
   // Check the childs 
   var childsAreValid = CheckChilds(item);
   result.Add(item.Id, childsAreValid);

   // Do some more 
// Item already checked/being checked
} else {
    // item.Id might not be in the result yet, but it will always be (otherwise it will never end up in the alreadySeenActions in the first place and not enter this else)
    // So what do I write here?
    var value = result[item.Id]

    if(value)
    // Do some more
}
  

Комментарии:

1. Я бы посмотрел на async await. learn.microsoft.com/en-us/dotnet/csharp/programming-guide /… и потокобезопасные коллекции learn.microsoft.com/en-us/dotnet/standard/collections /…

2. Поэтому в параллельном программировании важно, чтобы отдельные задачи были независимы друг от друга. «Ожидание» других задач — это то, чего следует избегать, если это возможно. Итак, разделите проверку на 2 отдельные задачи и добавьте их в очередь задач соответственно. Задача 1 «открыть узел» это задачи, которые открывают узел: проверяет, нужно ли добавлять задачи «открыть узел» для своих дочерних элементов, и проверяет, является ли узел конечным. Задача 2 «закрыть узел». Где задача 1 будет работать вниз, задача 2 работает вверх, она вычисляет действительность узла, затем проверяет всех родителей, если они теперь могут быть добавлены в качестве задачи «закрыть узел».

3. @Knoop это может сработать. Я попробую