Как я полагаю, вы уже сделали это самостоятельно, глядя на отраженный источник BlockingCollection, к сожалению, выглядит так, что, когда CancellationToken передается в BlockingCollection и он отменяется, вы получите исключение OperationCancelledException, как видно на рисунке ниже (спара обходных решений после изображения)
GetConsumingEnumerable
вызывает TryTakeWithNoTimeValidation
для BlockingCollection, что, в свою очередь, вызывает это исключение.
Обходной путь # 1
Одной из возможных стратегий будет, если вы будете иметь больше контроля над своими производителями и потребителями, чемпередав токен отмены в коллекцию BlockingCollection (что вызовет это исключение), вы передаете токен отмены своим производителям и своим потребителям.
Если ваши производители не производят, а ваши потребители не потребляют, товы фактически отменили операцию, не вызывая это исключение и передав CancellationToken.None в BlockingCollection.
Особые случаи Отмена, когда BlockingCollection имеет значение BoundedCapacity или Empty
Производители заблокированы : Потоки производителей будут заблокированы, когда BoundedCapacity на BlockingCollection имеет значениедостиг.Следовательно, при попытке отмены, когда BlockingCollection имеет значение BoundedCapacity (что означает, что ваши потребители не заблокированы, а производители заблокированы, поскольку они не могут добавлять какие-либо дополнительные элементы в очередь), вам потребуется разрешить использование дополнительных элементов (одиндля каждого потока производителей), который разблокирует производителей (поскольку они блокируются при добавлении в blockingCollection) и, в свою очередь, позволяет логике отмены срабатывать на стороне производителя.
Потребители заблокированы : Когда ваши потребители заблокированы из-за того, что очередь пуста, вы можете вставить пустую единицу работы (по одной для каждого потока потребителя) в коллекцию блокировки, чтобы разблокироватьпотребительские потоки и позволяют логике отмены работать на стороне потребителя.
Если в очереди есть элементы и не достигнут предел, такой как BoundedCapacity или Empty, то потоки производителей и потребителей не должны блокироваться.
Обходной путь # 2
Использование единицы отмены работы.
Когда ваше приложение необходимо отменить, тогда ваши производители (может быть, достаточно одного производителя, в то время как другие просто отменяют производство) будут производить единицу работы отмены (может быть нулевой, как вы также упомянули или какой-то класс, который реализует).интерфейс маркера).Когда потребители потребляют эту единицу работы и обнаруживают, что это на самом деле единица работы отмены, их логика отмены срабатывает. Количество единиц отмены работы, которая должна быть произведена, должно равняться количеству потоков потребителя.
Опять же, нужно быть осторожным, когда мы приближаемся к BoundedCapacity, поскольку это может быть признаком того, что некоторые производители заблокированы.В зависимости от количества производителей / потребителей вы можете потреблять потребителя, пока все производители (кроме 1) не отключатся.Это гарантирует, что вокруг не останется ни одного производителя.Когда остается только 1 производитель, ваш последний потребитель может отключиться, и производитель может прекратить производство единиц отмены работы.