Отмена задания с несколькими источниками - PullRequest
6 голосов
/ 07 июня 2011

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

Теперь у меня есть сценарий использования, в котором я хотел бы создать автоматический тайм-аут для отмены последовательности задач, если оператор не отвечаетсвоевременно (некоторые задачи ожидают взаимодействия оператора с физическим механизмом). В то же время мне все еще нужно поддерживать отмену, если управляющий класс Disposed.Я нашел CancellationTokenSource.CreateLinkedTokenSource , который звучит как то, что мне нужно, но у меня есть несколько проблем:

  1. Несколько рядов задач могут выполняться параллельно, поэтому янеобходимо создать новый CancellationTokenSource для отмены тайм-аута и связанный связанный источник для каждой серии задач, которую я начинаю.CancellationTokenSource реализует IDisposable, что означает, что мне нужно сохранить оба источника отмены и избавиться от них, когда последняя задача завершена или когда любой из подзадач отменен или не выполнен.Это кажется довольно неловким, даже с полезной магией закрытия анонимных методов (все еще имеют эти источники отмены.)

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

Я иду по правильному пути здесь илиЕсть ли более простой способ сделать это?

1 Ответ

9 голосов
/ 07 июня 2011

Основная проблема в вашем вопросе связана с вызовом Dispose() для ваших Task и / или CancellationTokenSource объектов. В этом случае я бы порекомендовал просто , а не , вызывая Dispose, что должно значительно упростить ваш дизайн.

В качестве оправдания я отсылаю вас к этой теме . В частности, Стивен Туб (премьер-министр, ответственный за задание) предлагает вам:

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

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

...