2013-03-21 6 views
3

У меня есть ConcurrentStack, каждый элемент которого является URL-адресом некоторого веб-ресурса. Также у меня есть N потоков (на самом деле Tasks), каждый из которых выталкивает один элемент из процесса стека и добавляет результат (результат - сбор) в этот стек или в другую очередь вывода в зависимости от некоторых критериев. Это нужно сделать, пока стек не станет пустым.Элементы стека процесса в нескольких потоках

Каков более элегантный способ распознать конец этого процесса и остановить выполнение этих задач? В других словах, как признать, что стек пуст, и нет выполнения задачи, которая будет добавить больше элементов в стек

+1

Вы описываете, как работают потребители, но ваш вопрос касается производителей. – adrianm

ответ

2

Условие завершения, как представляется, когда все задачи, прочитанные из стека, являются все ждет, когда элемент будет складываться в стек. Конечно, это может произойти только в том случае, если вы предоставите возможность для вашей задачи пассивно ждать этого события. Как было предложено другими ответами, вы можете использовать BlockingCollection поверх класса ConcurrentStack для реализации синхронизации.

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

1

Поскольку вы используете ConcurrentStack, который реализует IProducerConsumerCollection, вы можете обернуть его с BlockingCollection (создав один, используя this constructor). Это обеспечивает метод CompleteAdding(), который позволяет указывать конец данных.

Основание IProducerConsumerCollection будет использоваться для хранения элементов, поэтому оно будет по-прежнему вести себя как стек с точки зрения его LIFO.

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

Возможно, это может сработать для вас?

+0

Спасибо за ответ, я не знал о возможности расширения BlockingCollection как стека, но, однако, все мои потоки не знают, пришло ли время называть CompleteAdding или нет, потому что никто не знает, собираются ли другие добавьте больше элементов или нет –

+0

Ну что-то * должно знать - и что-то должно называть 'CompleteAdding()'. –

Смежные вопросы