C# Task任务取消

需求:

在使用Blazor开发工具时,有个需求:
扫码登录页面需要不断轮询接口获取扫码状态,并在对应的状态下进行对应的操作:刷新、登录、跳转等;
此时,为了不阻塞前端的响应,需要我们开启一个线程进行状态检测,并在完成后结束线程任务;

方案:

使用取消令牌(CancellationTokenSource);
相对操作比较简单,需要结束时调用Cancel(),同时,在Task内部进行IsCancellationRequested状态监听、或者使用暴力调用ThrowIfCancellationRequested()(同样需要不间断的调用,Cancel后才可触发,本质上也是校验IsCancellationRequested状态);

var cts = new CancellationTokenSource();
var tk = cts.Token;

// 将CancellationToken传入action中,然后对其取消状态进行跟踪
_ = Task.Factory.StartNew(async tk =>
{
    CancellationToken ct = (CancellationToken)tk;
    while (true)
    {
        ct.ThrowIfCancellationRequested();
        Console.WriteLine("循环中" + Thread.CurrentThread.ManagedThreadId);
        await Task.Delay(1000);
    }
}, tk, TaskCreationOptions.LongRunning);

// OR

// 此处是对于取消注册个回调方法,在取消后进行调用
_ = Task.Factory.StartNew(async tk =>
{
    var state = true;
    CancellationToken ct = (CancellationToken)tk;
    ct.Register(() => 
    {
        state = false;
    });
    while (state)
    {
        Console.WriteLine("循环中" + Thread.CurrentThread.ManagedThreadId);
        await Task.Delay(1000);
    }

}, tk, TaskCreationOptions.LongRunning);

注意:

  • 在使用Task.Run() 或 Task.Factory.StartNew()时,有个参数为传入CancellationToken,如:Run(Action, CancellationToken);该cancellationToken不会传递到Task内,更不会对Task内不造成影响,该cancellationToken 只是用于取消Run() 或 StartNew();
  • ck.Register可进行多次,构成链表执行,链表为倒叙的(最先注册的最后执行);

扩展

CancellationTokenSource 具体实现源码解析:浅谈C#取消令牌CancellationTokenSource
相关项目:WeComLoad Demo

posted @ 2022-04-10 12:34  Memoyu  阅读(1711)  评论(0编辑  收藏  举报