【发布时间】:2021-05-05 17:24:41
【问题描述】:
我正在尝试使用取消令牌从另一个线程中跳出循环:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace CancellationTokenTest
{
class Program
{
private static CancellationTokenSource token;
static async Task Main(string[] args)
{
token = new CancellationTokenSource();
var t1 = LongProcess1();
for (int i = 0; i < 5; i++)
{
try
{
await Task.Delay(2000, token.Token);
Console.WriteLine($"Main awaited {i}");
}
catch (OperationCanceledException)
{
break;
}
}
Console.WriteLine("Main loop completed");
t1.Wait();
Console.WriteLine("Application end");
}
static async Task LongProcess1()
{
for (int i = 0; i < 5; i++)
{
await Task.Delay(1000);
Console.WriteLine($"LongProcess1 awaited {i}");
}
Console.WriteLine("Submitting cancel");
token.Cancel(); // <------ Blocking execution
Console.WriteLine("Cancellation done!");
}
}
}
问题是Console.WriteLine("Cancellation done!"); 行永远不会被执行,Main() 方法一直在等待t1 完成。
我不明白为什么!
我在 .NET 5 上运行它,但它似乎并不依赖于框架。 有人可以帮助我了解发生了什么吗?
【问题讨论】:
-
删除
t1.Wait();。这导致了僵局。当Cancel()被调用时,线程进入回到Main中的for循环 - 但随后该线程被t1.Wait()阻塞,这将阻止它继续进入LongProcess1. -
我注意到您的程序不是多线程的 - 这就是它遇到死锁的原因。最好的解决方案不是开始使用线程,而是继续使用单线程,消除老式的阻塞操作。
-
如果我删除了
t1.Wait()“取消完成!”发生在“应用程序结束”之后(我认为不可能......)。在 Cacel 之后添加延迟会导致“取消完成!”永远不会发生。有没有办法让它在“应用程序结束”之前发生? -
@Dai .... 你开发过一个单一的多线程应用程序吗?
-
@MartinJames 我承认当我写到“程序不是多线程的”这在技术上是不正确的(事实上,斯蒂芬的回答说,它使用线程池)。我的意思是,OP 的程序 在任何时间点都只会有一个运行用户代码的线程 - 并不是说在他们的进程的用户代码中永远存在一个线程 -还是您有不同的看法?
标签: c# multithreading async-await task-parallel-library cancellation-token