CancellationToken甚至为null

时间:2018-10-30 16:05:27

标签: c# task

在我的应用程序中,我运行一个执行繁重操作的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

4 个答案:

答案 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是多余的,您甚至不必初始化它。

未等待Start方法中的

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);
        }
    }
}