时间:2021-07-01 10:21:17 帮助过:29人阅读
public class Example
{
public static void Main()
{
CancellationTokenSource cts = new CancellationTokenSource();
var thread = new Thread(ThreadWork);
thread.Start(cts.Token);
while (true)
{
if(Console.ReadKey().KeyChar == 'c')
{
Console.WriteLine("请求取消线程的执行");
cts.Cancel();
break;
}
}
Console.ReadLine();
}
private static void ThreadWork(object state)
{
CancellationToken cancellationToken = (CancellationToken)state;
while (true)
{
// 检查是否取消
if(cancellationToken.IsCancellationRequested)
{
Console.WriteLine("线程已经取消了");
Console.WriteLine("线程的资源已经清理完成。");
break;
}
// 模拟工作
Thread.SpinWait(500000);
Console.WriteLine("我还在工作。");
}
}
}
取消阻塞的线程
上面的示例中,后台线程会长时间进行计算,但更多的时候,线程会由于等待某个事件,从而进入阻塞状态。这个时候,实际上线程已经不再执行状态了,很明显,它没有机会去检查取消标志。 那么,该如何解决这个问题呢?CancellationToken的WaitHandle属性提供了解答。WaitHandle类有一个静态方法WaitAny,它可以同时等待多个事件,当多个事件中的任意一个有效时,线程都会从阻塞状态中返回。可以根据WaitAny方法的返回值来判断发生了什么事件,从而相应的执行代码。例子:
代码如下:
public class Example
{
private static int Value;
public static void Main()
{
var autoResetEvent = new AutoResetEvent(false);
var cts = new CancellationTokenSource();
var state = new { ValueAvailableEvent = autoResetEvent, CancellationToken = cts.Token };
var threadConsumer = new Thread(ConsumerThreadWork);
var threadProducter = new Thread(ProducterThreadWork);
threadConsumer.Start(state);
threadProducter.Start(state);
while (true)
{
if (Console.ReadKey().KeyChar == 'c')
{
Console.WriteLine("请求取消线程的执行");
cts.Cancel();
break;
}
}
Console.ReadLine();
}
public static void ProducterThreadWork(dynamic state)
{
var valueAvailableEvent = (AutoResetEvent)state.ValueAvailableEvent;
var cancellationToken = (CancellationToken)state.CancellationToken;
var rand = new Random();
while (!cancellationToken.IsCancellationRequested)
{
Value = rand.Next();
Console.WriteLine("\r\n产生一个值{0}", Value);
valueAvailableEvent.Set();
Thread.Sleep(500);
}
Console.WriteLine("生产者线程被取消。");
}
public static void ConsumerThreadWork(dynamic state)
{
var valueAvailableEvent = (AutoResetEvent)state.ValueAvailableEvent;
var cancellationToken = (CancellationToken)state.CancellationToken;
var events = new[] { valueAvailableEvent, cancellationToken.WaitHandle };
while (true)
{
var eventIndex = WaitHandle.WaitAny(events);
// 处理数据
if (eventIndex == 0)
{
Console.WriteLine("处理值{0}。", Value);
}
// 处理取消事件
else if (eventIndex == 1)
{
Console.WriteLine("消费者线程被取消。");
break;
}
}
}
}
在上面的例子中,有三个线程,分别是UI线程,生产者线程和消费者线程。其中生产者线程每隔一秒产生一个有效数值,并将数据保存到Value字段中,而消费者线程等待值的产生,这个等待的过程是阻塞的。消费都线程通过WaitHandle.WaitAny方法来同时等待值有效事件或者取消事件,当任意一个事件有效时,线程都将继续,并且通过返回的值来判断发生的事件,并作相应的处理。
总结
多线程模型中的线程取消问题还是比较复杂的。Thread.IsBackground属性提供了在前台线程结束后自动结束线程的方法。Thread.Abort方法提供了一种“粗暴”的结束线程的方法。CancellationTokenSource类则是线程取消的标准模式,我们应当更多的使用这种模式。文章写的不多,基本是字数不够,代码来凑,大家伙将就的看看吧。