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();
}
}
从控制台应用程序启动此代码主要方法:
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,链接令牌源等待它自己的回调完成以设置此标志。
要解决这个问题,只需删除回调,或者以不阻塞等待相关任务完成的方式编写,或者将任务更改为不等待 linked 令牌来源 IsCancellationRequested 标志。
如果有人能帮助我,请帮忙。 我正在尝试使用 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();
}
}
从控制台应用程序启动此代码主要方法:
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,链接令牌源等待它自己的回调完成以设置此标志。
要解决这个问题,只需删除回调,或者以不阻塞等待相关任务完成的方式编写,或者将任务更改为不等待 linked 令牌来源 IsCancellationRequested 标志。