繁体   English   中英

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

[英]C# Task - Linked cancellation token not working

如果有人可以帮助我,请。 我正在尝试使用TPL链接的取消令牌。 问题是,在取消了主要的CancellationTokenSource之后,链接令牌的属性IsCancellationRequested的值仍为“ false”。

可以肯定的是,我正在开始两项任务-但这应该是同一件事。 我向第一个传递CancellationToken,向第二个传递CancellationTokenSource。 行为是相同的:在while循环中-取消条件后,条件linkedToken.IsCancellationRequested保持为“ 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();
    }
}

要从控制台应用程序的Main方法启动此代码:

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

            Thread.Sleep(5000);
            manager.Cancel();
   }
}

谢谢您的帮助!

此问题的根源是以下行:

this.mainToken.Register(MainCanceled);

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

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

因此,该回调将在相关任务完成之前完成。 在任务中,您可以执行此操作

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

因此,直到请求取消,任务才能完成。

现在到棘手的部分:创建链接令牌源时

CancellationTokenSource.CreateLinkedTokenSource(mainToken)

将投入回调父(mainToken)令牌源的列表。 执行此回调后,链接令牌源也将被取消。 此回调将在列表中的回调之后

因此,您陷入僵局,因为第一个回调(您的)等待任务完成,任务等待链接令牌IsCancellationRequested等于true,并且链接令牌源等待它自己的回调完成以设置此标志。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM