Как я могу заставить поток ждать, пока другой поток не будет ждать (С#)

У меня есть потребительский поток, который создает несколько рабочих потоков. Эти потоки должны переключаться между активным и ожидающим состояниями. Когда все рабочие потоки находятся в состоянии ожидания, это означает, что текущее задание выполнено. Как заставить потребительский поток ждать, пока все рабочие потоки перейдут в состояние ожидания? Я хочу, чтобы поведение было очень похоже на Thread.Join() во всех рабочих потоках, однако я хочу, чтобы потоки продолжали работать для следующего задания. Я не могу создавать новые потоки, потому что задания находятся в жестком цикле, а создание новых потоков требует больших затрат.


person evg02gsa3    schedule 08.02.2017    source источник
comment
Вы должны использовать явные рабочие потоки? Разве вы не можете представить их как Задачи вместо этого? Затем используйте Task .WhenAll, чтобы проверить, все ли задачи завершены. Если вам нужно использовать потоки, посмотрите AutoResetEvents и WaitHandle.WaitAll.   -  person Ilian    schedule 08.02.2017
comment
Да, Задачи могли бы работать лучше. Я не был так уверен, что в версии .net, которую я использовал, были задачи. Может быть, неправильно создавать задачи в тесном цикле, потому что я использую Mono на Xamarin, а сборщик мусора не очень хорош.   -  person evg02gsa3    schedule 08.02.2017


Ответы (2)


Насколько я знаю, нет механизма, чтобы делать то, что вы хотите. (Thread.Join, но, поскольку вы не можете заблокировать, это не вариант)

Судя по предоставленной вами информации, похоже, что вы действительно строите конечный автомат, только для нескольких потоков.

Я бы создал Singleton и использовал бы его как конечный автомат. Потоки могут сигнализировать статусу Singleton.

Похоже, у вас есть неопределенное количество потоков, поэтому вам нужно будет поместить статус каждого в коллекцию. Я бы посмотрел здесь Thread Safe Collections чтобы найти правильный способ хранения информации о состоянии.

Надеюсь это поможет.

person Kelly    schedule 08.02.2017

Извиняюсь за краткий ответ (может быть расширен позже), но вы, вероятно, WaitHandle.WaitAll в сочетании с ManualResetEvent. Вы должны передавать свои объекты ManualResetEvent в каждый рабочий поток при их создании, сигнализировать им, когда они становятся бездействующими, и передавать весь набор дескрипторов в метод WaitHandle.WaitAll, чтобы разбудить наблюдающий поток, когда они будут завершены. Вы также можете использовать функцию тайм-аута этого метода, если вы хотите периодически запускать какую-то задачу во время ожидания или выполнять какую-то операцию, если задача занимает слишком много времени.

Обратите внимание, что если ваши рабочие потоки предназначены для завершения после завершения операции (не совсем ясно, если это так), может быть более подходящим порождать их как задачи и использовать Task.WaitAll.

Редактировать: при быстром повторном прочтении кажется, что вы действительно хотите использовать задачи, а не пытаться повторно использовать полные рабочие потоки. Задачи используют потоки, которые были выделены из пула потоков, что устраняет накладные расходы на создание потока, о которых вы беспокоились, потому что потоки (обычно) будут готовы и ожидают работы. Вы можете просто создавать каждую задачу и ждать, пока они все будут выполнены.

person Roger Sanders    schedule 08.02.2017