2013-06-06 2 views
2

У меня возникли проблемы с остановкой задачи. Во-первых, я только начал использовать Задачи. Раньше я использовал делегат.BeginInvoke() для работы в фоновом режиме, но на этот раз мне нужно остановить фоновое выполнение, если это необходимо. Поэтому я переключился на «Задачи». Это мой код:Не удается отменить задачу с помощью CancellationTokenSource.Cancel()

CancellationTokenSource token = new CancellationTokenSource(); 
Task posting = Task.Factory.StartNew(() => DoPosting(docs, session), token.Token); 
HttpRuntime.Cache[session.ToString() + "_token"] = token; 
HttpRuntime.Cache[session.ToString() + "_task"] = posting; 

Это ASP.NET MVC, поэтому я храню долговечные вещи в HttpRuntime.Cache. Пользователь может отменить операцию с помощью этого действия:

public JsonResult StopPosting(string session) 
{ 
    CancellationTokenSource token = (CancellationTokenSource)HttpRuntime.Cache.Get(session.ToString() + "_token"); 
    Task posting = (Task)HttpRuntime.Cache[session.ToString() + "_task"]; 
    token.Cancel(); 

    return Json(new { Message = "Stopped!" }); 
} 

Теперь, когда это действие попадает в первый раз, ничего не происходит. Затем я запрашиваю отмену во второй раз. Теперь, token.IsCancellationRequested говорит «true», поэтому token.Cancel() должен что-то сделать. Но posting.Status все еще «работает». Он будет оставаться таким, пока он не завершится, а затем «RunToCompletion».

Итак, я попросил отменить задание, но он был отменен.

Возможно, я что-то делаю неправильно, или мне не хватает чего-то очевидного, но я просто не могу понять/понять, почему он не отменит.

Возможно, кто-то может пролить свет?

С уважением.

+0

У вас есть что-нибудь в вашем методе DoPosting, который периодически проверяет состояние токена и, если необходимо, выходит из него? См. Это для примера: _ [Отмена в управляемых потоках] (http://msdn.microsoft.com/en-us/library/dd997364.aspx) _ –

+0

Совсем нет. Он выполняет тяжелую работу с базой данных. Я знаю, что я должен позаботиться о том, что там происходит, но я не могу преодолеть первое препятствие. Спасибо за ссылку. –

ответ

7

Отмена маркера не сразу приведет к тому, что делегат задачи прекратит выполнение прямо там, где он есть. Подтверждение того, что (как это делается через Abort через потоки), может вызвать всевозможные ошибки, начиная от объектов, которые не очищаются должным образом, нарушаются инварианты из-за выполнения, останавливая часть пути через операцию, которая должна быть логически замечена как атомарная и т. Д. .

Что вам нужно сделать, так это выполнить фактическую выполняемую функцию, посмотреть на CancellationToken и периодически проверять, что она не была отменена. В дополнение к передаче токена до StartNew вам необходимо передать его методу DoPosting. Затем этот метод должен периодически вызывать token.ThrowIfCancellationRequested(); в местах в методе, где было бы целесообразно остановиться, если бы действительно было исправлено аннулирование.

См. How do I cancel non-cancelable async operations? для дальнейшего ознакомления.

+0

Хорошо, я понимаю, что вы говорите. Будет так. Но, к моему мнению, все еще один вопрос. В любом случае, какой хороший токен, я мог бы проверить DoPosting на флаг и получить тот же результат. Просто спрашивать, какие преимущества токена отмены? –

+1

@MilosMijatovic Существует несколько факторов. Первое касается вопросов синхронизации.«CancellationToken» - это не намного больше, чем обертка вокруг bool, но он использует соответствующие барьеры памяти и т. Д., Чтобы обеспечить правильное наблюдение/изменение мутации из разных потоков. Затем он позволяет «Задаче» различать отмену и просто заканчивать нормально или сбрасывать исключение, что позволяет продолжать действовать по-разному для отмененной задачи (часто полезно). Наконец, он позволяет отмечать «Задачу» как отмененную до ее начала. – Servy

+0

Спасибо. Хорошие моменты. Мне определенно нужно еще кое-что прочитать по этой теме. –

2

Я думаю, вы, вероятно, ожидаете слишком много CancellationToken. Что касается задач, я думаю, что CancellationToken используется только при определении того, следует ли запускать задачу, когда для этой задачи доступен слот. После запуска задачи структура задачи не может просто прервать вызов делегата, когда CancellationToken будет отменен. Чтобы полностью отменить что-то вроде этого, код, который вызывается инфраструктурой Task (DoPosting), должен быть написан, чтобы быть в курсе CancellationToken и должен проверять состояние этого токена непосредственно в соответствующих точках кода.

+0

Спасибо за ваш вклад Майкл, также. Я ожидал слишком многого. –

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