Не рад этой невозможности прерывания потока вообще.Пример;
У вас есть простое приложение Windows Form, которое подключается к блокирующему синхронному веб-сервису.В рамках которого он выполняет функцию веб-службы в параллельном цикле.
Parallel.ForEach(iListOfItems, po, (item, loopState) =>
{
ParallelProcessIntervalRequest(wcfProxyClient, item, loopState);
});
Вызов веб-службы занимает 2 минуты для завершения в avg (в действительности это может быть любой блокирующий вызов, например Thread.Sleep).вместо этого, не просто веб-сервис) Теперь я установил свой MaxDegreeOfParallelism на прагматические 20 потоков.В iListOfItems есть 1000 элементов для обработки.
Пользователь нажимает кнопку процесса, и цикл начинается, очень приятно, что у нас есть 20 потоков, работающих на 1000 элементов в коллекции iListOfItems.Отлично.
Однако пользователю по какой-то причине необходимо закрыть приложение, а затем закрыть форму.Эти 20 потоков будут продолжать превышать все 1000 элементов, что было бы не хорошо, если бы до сих пор обрабатывалось, может быть, только 40, а теперь это было бы довольно плохо, поскольку приложение не будет закрываться, как того ожидает пользователь, но будет продолжать работать засцены, как видно в диспетчере задач.
Скажем, пользователь пытается заново собрать приложение в VS 2010, он сообщает, что исполняемый файл все еще заблокирован, ему придется зайти в диспетчер задач и убить его.
Ваш крик, но, конечно, вы должны отменять указанные потоки, используя новые конструкции параллельного отмены ... но вы знаете, ситуация не становится намного лучше, пользователю все равно придется ждать, пока последний вызов блокировки не завершится, что в нашем примере здесь составляет 2 минуты.Есть еще много сценариев, для которых это поведение вызывает проблемы.
Поэтому я решил не вызывать функцию Cancel объекта CancellationTokenSource, поскольку это вызывает исключение, которое является дорогостоящим, а также, возможно, нарушает антипаттен управленияпоток кода по исключениям.Поэтому я реализую простое свойство, безопасное для потоков - StopExecuting.Внутри цикла я проверяю значение StopExecuting и, если установлено значение true внешним воздействием, я делаю следующий вызов из цикла;
if (loopState.ShouldExitCurrentIteration || loopState.IsExceptional || StopExecuting) {loopState.Stop(); return;}
Таким образом, итерация может завершиться «контролируемым» способом вместе состановка цикла, обрабатывающего дальнейшие итерации, но, как я уже сказал, это мало что дает для нашей дилеммы.
Длинный блокирующий вызов, выполняемый в итерации, должен завершиться, прежде чем мы сможем проверить, должны ли мы остановиться.Таким образом, когда пользователь закрывает форму, возможно, 20 потоков попросили остановить, но они остановятся только после того, как завершат выполнение там длительного вызова функции - что может составить 2 минуты в среднем.
То же самоеверно для вызова Отмена на CancellationTokenSource.Только после того, как итерация закончена (не прервана, как прерывание потока), исключение кэшируется, готово к тому времени, когда все другие потоки в конечном итоге завершаются и возвращаются.Вызов Cancel при CancellationTokenSource, по-видимому, не создает исключение в потоке обработки, которое прервало бы блокирующий вызов, как прерывание потока.
Если это произойдет, это в любом случае не будет отличаться от вызова прерывания потока в потоке, поскольку оба способа приводят к исключению, которое может быть перехвачено в потоке, чтобы иметь дело с закрытием и освобождением ресурсов и т. д. до выхода из потока.
Исключение прерывания потока - это то место, где вы можете смягчить требование "оставляя систему в нестабильном / неопределенном состоянии ", если произойдут непредвиденные обстоятельства, такие как закрытие формы, чтобы впоследствии сказать, что иногда это может быть невозможным, и программисту действительно нужно убедиться в том, что они кодируют код.цикл и, действительно, какие ресурсы они выбрали для поддержки.Принимая во внимание все обстоятельства, невозможность прерывать блокирующие вызовы с помощью прерывания потока, подобного поведению, кажется, что инструмент был потерян из-за нашей хитрости.Мне пришлось бы вернуться к нормальным конструкциям потоков в таких случаях, чтобы получить эту единственную, но важную способность.Позор.
Так это проблема, короткое замыкание в новой параллельной библиотеке? Если нет, то как библиотека позволяет нам убивать эти потоки, когда форма закрыта, не дожидаясь блокировки вызовов или не оставляя процесс запущенным за кулисами. Конечно, такой контроль был бы относительно простым, если бы мы использовали «старые» потоковые примитивы и реальные потоки.