如何使用取消令牌在 C# 中取消被阻止的任务
本文关键字:取消 任务 何使用 令牌 | 更新日期: 2023-09-27 17:55:21
我有一个任务总是被阻止,我有一个CancelToken传递给它,用于取消任务。但是,永远不会执行设置为在任务取消时执行的继续任务。代码为:
_tokenSrc = new CancellationTokenSource();
var cnlToken = _tokenSrc.Token;
Task.Run(() =>
// _stream.StartStream() blocks forever
_stream.StartStream(), cnlToken)
.ContinueWith(ant =>
{
_logger.Warn("Stream task cancellation requested, stopping the stream");
_stream.StopStream();
_stream = null;
_logger.Warn("Stream stopped and task cancelled");
}, TaskContinuationOptions.OnlyOnCanceled);
稍后在代码中的其他地方...
_tokenSrc.Cancel();
我不得不使用任务进行_stream的原因。StartStream() 是这个调用永远阻塞(一个我无法控制的 api,请注意,_stream指的是从 Web 服务流式传输数据的第三方 Api),所以我不得不在另一个线程上调用它。
取消任务的最佳方法是什么?
[更新]
我将代码更改为以下代码,从而解决了问题:
Task.Run(() =>
{
var innerTask = Task.Run(() => _stream.StartStream(), cToken);
innerTask.Wait(cToken);
}, cToken)
.ContinueWith(ant =>
{
_logger.Warn("Stream task cancellation requested, stopping the stream");
_stream.StopStream();
_stream = null;
_logger.Warn("Stream stopped and task cancelled");
}, TaskContinuationOptions.OnlyOnCanceled);
您可以在CancellationToken
上使用 Register
方法来注册将在请求取消时调用的委托。在委托中,调用取消阻止被阻止的操作的方法。
像这样:
_tokenSrc = new CancellationTokenSource();
var cnlToken = _tokenSrc.Token;
var task = Task.Factory.StartNew(() =>
{
using(var tokenReg = cnlToken.Register(() =>
{
_logger.Warn("Stream task cancellation requested, stopping the stream");
_stream.StopStream();
_stream = null;
_logger.Warn("Stream stopped and task cancelled");
}))
{
_stream.StartStream(), cnlToken)
}
}, cnlToken);
MSDN"如何:注册取消请求的回调"
如何使用取消令牌在这里清楚地描述:http://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx并建议遵循模式。
我将报告该示例,以防页面出现故障:
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main()
{
var tokenSource2 = new CancellationTokenSource();
CancellationToken ct = tokenSource2.Token;
var task = Task.Factory.StartNew(() =>
{
// Were we already canceled?
ct.ThrowIfCancellationRequested();
bool moreToDo = true;
while (moreToDo)
{
// Poll on this property if you have to do
// other cleanup before throwing.
if (ct.IsCancellationRequested)
{
// Clean up here, then...
ct.ThrowIfCancellationRequested();
}
}
}, tokenSource2.Token); // Pass same token to StartNew.
tokenSource2.Cancel();
// Just continue on this thread, or Wait/WaitAll with try-catch:
try
{
task.Wait();
}
catch (AggregateException e)
{
foreach (var v in e.InnerExceptions)
Console.WriteLine(e.Message + " " + v.Message);
}
Console.ReadKey();
}
}
这里有一个更深入的示例:http://msdn.microsoft.com/en-us/library/dd537607(v=vs.110).aspx但第一个应该足以满足你的方案。