c#任务-链接的取消令牌不起作用

本文关键字:取消 令牌 不起作用 链接 任务 | 更新日期: 2023-09-27 18:17:19

如果有人能帮助我。我正在尝试使用与TPL相关的取消令牌。问题是取消主CancellationTokenSource后,链接令牌的属性IsCancellationRequested的值仍然为"false"。

我开始两个任务,只是为了确保-但它应该是相同的事情。我向第一个传递CancellationToken,向第二个传递CancellationTokenSource。行为是相同的:在while循环条件linkedToken。iscancellationrequest在取消后保持"false"

下面是我使用的代码:
public class Manager
{
    private Task tokenTask;
    private Task sourceTask;
    private CancellationTokenSource mainCancelationTokenSource;
    private CancellationToken mainToken;
    public Manager()
    {
        this.mainCancelationTokenSource = new CancellationTokenSource();
        this.mainToken = mainCancelationTokenSource.Token;
        this.mainToken.Register(MainCanceled);
    }
    public void Start()
    {
        Workers w = new Workers();
        tokenTask = Task.Run(() => w.DoWorkToken(mainToken), mainToken);
        sourceTask = Task.Run(() => w.DoWorkSource(mainCancelationTokenSource), mainCancelationTokenSource.Token);
    }
    public void Cancel()
    {
        mainCancelationTokenSource.Cancel();
    }
    private void MainCanceled()
    {
        try
        {
            tokenTask.Wait();
        }
        catch (Exception e)
        {
        }
        try
        {
            sourceTask.Wait();
        }
        catch (Exception e)
        {
        }
    }
}
class Workers
{
    public void DoWorkToken(CancellationToken mainToken)
    {
        CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(mainToken);
        CancellationToken linkedToken = linkedCts.Token;
        while (!linkedToken.IsCancellationRequested)
        {
            Random r = new Random();
            Task.Delay(200 * r.Next(1, 11)).Wait();
        }
        linkedToken.ThrowIfCancellationRequested();
    }
    public void DoWorkSource(CancellationTokenSource mainCts)
    {
        CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(mainCts.Token);
        while (!linkedCts.Token.IsCancellationRequested)
        {
            Random r = new Random();
            Task.Delay(200 * r.Next(1, 11)).Wait();
        }
        linkedCts.Token.ThrowIfCancellationRequested();
    }
}

从控制台应用程序启动此代码

class Program
{
    static void Main(string[] args)
    {
            Manager manager = new Manager();
            manager.Start();
            //Console.ReadKey();
            Thread.Sleep(5000);
            manager.Cancel();
   }
}

谢谢你的帮助!

c#任务-链接的取消令牌不起作用

这个问题的根源是这一行:

this.mainToken.Register(MainCanceled);

注册一个回调,当令牌被取消时执行。在内部,该回调被委托给父CancellationTokenSource,并放在一些回调列表中,以便在请求取消源时执行。在处理程序中,你做

tokenTask.Wait();
sourceTask.Wait();

所以这个回调将不会完成,直到相关的任务完成。在任务中你这样做

while (!linkedToken.IsCancellationRequested) {
    // loop here
}

因此任务将不会完成,直到请求取消。

现在是棘手的部分:当您创建链接令牌源

CancellationTokenSource.CreateLinkedTokenSource(mainToken)

它将在父(mainToken)令牌源列表中放置一个回调。当这个回调被执行时,链接的令牌源也被取消。这个回调将在列表中的之后的

所以你是死锁的,因为第一个回调(你的)等待任务完成,任务等待链接令牌IsCancellationRequested等于true,链接令牌源等待它自己的回调完成来设置这个标志。

要解决这个问题,只需删除回调,或者以一种不阻塞等待相关任务完成的方式编写,或者将任务更改为不等待链接的令牌源IsCancellationRequested标志。