Отмена задачи с несколькими источниками

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

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

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

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

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


person Dan Bryant    schedule 07.06.2011    source источник


Ответы (1)


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

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

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

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

person Reed Copsey    schedule 07.06.2011
comment
@Dan: Я знаю, но помните, что любой правильно реализованный объект IDisposable будет очищен финализатором, если вы не вызовете для него Dispose(). Я считаю, что вам всегда следует пытаться вызвать Dispose() любой IDisposable объект, но в некоторых случаях вы делаете свою жизнь намного хуже, чем просто оставляете это на усмотрение финализатора. TPL - одна из тех областей, где все становится нечетким - очень часто (IMO) намного лучше не Dispose() объекты TPL, потому что работа, необходимая для их выполнения, с гораздо большей вероятностью приведет к проблемам с обслуживанием и ошибкам. - person Reed Copsey; 07.06.2011
comment
Я определенно понимаю вашу точку зрения (с практической точки зрения, с точки зрения выполнения работы), и, вероятно, именно этим я и займусь, но эти ситуации «меньшего из двух зол» меня раздражают. На данный момент, однако, возражение носит скорее философский, чем технический характер, и никакие инженерные разработки не могут его разрешить. - person Dan Bryant; 07.06.2011
comment
@Dan: Я знаю, что ты имеешь в виду - меня раздражает то, что я не выбрасываю что-то специально - но, в конце концов, это гораздо меньшее из зол .... - person Reed Copsey; 07.06.2011