在我的应用程序中,我运行一个执行繁重操作的Task
,我试图停止执行该Task
。实际上,我在课堂上声明了以下结构:
public class Foo
{
private CancellationTokenSource tokenSource = new CancellationTokenSource();
private CancellationToken token;
public void Start()
{
var task = new Task(async () => {
try
{
await new Bot().StartAsync(token);
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
}, token));
task.Start();
}
}
如您所见,我已经声明了CancellationTokenSource
,当用户单击按钮时,它允许我停止任务执行:
StopTask_Click(object sender, EventArgs e)
{
tokenSource.Cancel();
}
现在,在StartAsync
方法中,我有以下代码:
public async Task StartAsync(CancellationToken token)
{
ApplicationToken = token;
while(true)
{
if(ApplicationToken.IsCancellationRequested)
{
break;
}
}
}
ApplicationToken
将作为参数传递的令牌存储在StartAsync
方法的类中。
在按钮单击事件之后,该请求应该被取消,但是什么也没有发生。
然后我检查每次迭代是否发出取消请求,但变量值甚至为false
。
答案 0 :(得分:2)
好吧,看来您忘记了token = tokenSource.Token;
Edit1:您应使用ThrowIfCancellationRequested()
Edit2:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace CancellationTokenPOC
{
class Program
{
public static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
TokenPOC t = new TokenPOC();
var longRunningTask = Task.Factory.StartNew(async () =>
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
t.token.ThrowIfCancellationRequested();
await Task.Delay(10000);
}
});
Console.ReadKey();
t.source.Cancel();
await Task.Delay(1000);
Console.WriteLine("finishing");
}
}
class TokenPOC
{
public CancellationTokenSource source = new CancellationTokenSource();
public CancellationToken token;
public TokenPOC()
{
token = source.Token;
}
}
}
此令牌被取消并按预期结束程序...
答案 1 :(得分:0)
您传递的令牌与尝试取消的令牌不同。您可以消除
private CancellationToken token;
而是传递到StartAsync()
tokenSource.Token
答案 2 :(得分:0)
您可以尝试以下操作吗:
public class Foo
{
var cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token();
public void Start() {
var t = Task.Factory.StartNew(() =>
{
try
{
await new Bot().StartAsync(token);
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
}, token).ContinueWith(task =>
{
if (!task.IsCompleted || task.IsFaulted)
{
// Log
}
}, token);
}
StopTask_Click(object sender, EventArgs e)
{
cancellationTokenSource.Cancel();
}
}
答案 3 :(得分:0)
首先,StartAsync
缺少等待操作符,它将同步运行。
public async Task StartAsync(CancellationToken token)
{
ApplicationToken = token;
while (true)
{
if (ApplicationToken.IsCancellationRequested) break;
await Task.Delay(10, ApplicationToken); // => you may change it to concrete task
}
}
第二,CancellationToken
类中的Foo
是多余的,您甚至不必初始化它。
new Bot().StartAsync(tokenSource.Token);
,因此在调用完成之前,将继续执行当前方法。
由于Start
方法无效,因此您应该使用GetAwaiter()
方法才能在Bot
类中执行任务。
public void Start()
{
try
{
new Bot().StartAsync(tokenSource.Token).GetAwaiter();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
最后,如果StopTask_Click
方法是Foo
类的成员,那么它应该可以正常工作。
这是一个如何使用CancellationTokenSource
public partial class Form1 : Form
{
private readonly Foo foo = new Foo();
private void button1_Click(object sender, EventArgs e)
{
foo.Start();
}
private void button2_Click(object sender, EventArgs e)
{
foo.Cancel();
}
}
public class Foo
{
private readonly CancellationTokenSource tokenSource = new CancellationTokenSource();
public void Start()
{
try
{
new Bot().StartAsync(tokenSource.Token).GetAwaiter();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
public void Cancel()
{
tokenSource.Cancel();
}
}
public class Bot
{
private CancellationToken ApplicationToken;
public async Task StartAsync(CancellationToken token)
{
ApplicationToken = token;
while (true)
{
if (ApplicationToken.IsCancellationRequested) break;
await Task.Delay(10, ApplicationToken);
}
}
}