C#多线程之线程基础篇( 四 )


??如果是自己设计的阻塞,完全可以用 信号构造(signal structure) 或者 取消令牌(cancellation tokens) 来达到相同效果,且更加安全 。如果希望结束他人代码导致的阻塞,Abort总是更合适
中止(Abort)通过Thread.Abort方法也可以使阻塞的线程被强制释放,效果和调用Interrupt类似,不同的是它抛出的是ThreadAbortException的异常 。另外,这个异常会在catch块结束时被重新抛出(试图更好的结束线程) 。
Thread t = new Thread(delegate(){try{while (true){}}catch (ThreadAbortException){_testOutputHelper.WriteLine("收到中止信号");}// 这里仍然会继续抛出ThreadAbortException,以保证此线程真正中止});_testOutputHelper.WriteLine(t.ThreadState.ToString()); // Unstarted 状态t.Start();Thread.Sleep(1000);_testOutputHelper.WriteLine(t.ThreadState.ToString()); // Running 状态t.Abort();_testOutputHelper.WriteLine(t.ThreadState.ToString()); // AbortRequested 状态t.Join();_testOutputHelper.WriteLine(t.ThreadState.ToString()); // Stopped 状态除非Thread.ResetAbort在catch块中被调用,在此之前,线程状态(thread state) 是AbortRequested,调用Thread.ResetAbort来阻止异常被自动重新抛出之后,线程重新进入Running状态(从这开始,它可能被再次中止)
static void Main(){Thread t = new Thread (Work);t.Start();Thread.Sleep (1000); t.Abort();Thread.Sleep (1000); t.Abort();Thread.Sleep (1000); t.Abort();}static void Work(){while (true){try { while (true); }catch (ThreadAbortException) { Thread.ResetAbort(); }Console.WriteLine ("我没死!");}}Thread.Abort在NET 5被弃用了:https://learn.microsoft.com/zh-cn/dotnet/core/compatibility/core-libraries/5.0/thread-abort-obsolete

未处理的ThreadAbortException是仅有的两个不会导致应用程序关闭的异常之一,另一个是AppDomainUnloadException 。
Abort几乎对处于任何状态的线程都有效:Running、Blocked、Suspended以及Stopped 。然而,当挂起的线程被中止时,会抛出ThreadStateException异常 。中止会直到线程之后恢复时才会起作用 。
try { suspendedThread.Abort(); }catch (ThreadStateException) { suspendedThread.Resume(); }// 现在 suspendedThread 才会中止Interrupt和Abort最大的不同是:调用Interrupt线程会继续工作直到下次被阻塞时抛出异常,而调用Abort会立即在线程正在执行的地方抛出异常(非托管代码除外) 。
这将导致一个新的问题:.NET Framework 中的代码可能会被中止,而且不是安全的中止 。如果中止发生在FileStream被构造期间,很可能造成一个非托管文件句柄会一直保持打开直到应用程序域结束 。
协作取消模式【C#多线程之线程基础篇】正如上面所说Interrupt和Abort总是危险的,替代方案就是实现一个协作模式(cooperative ):工作线程定期检查一个用于指示是否应该结束的标识,发起者只需要设置这个标识,等待工作线程响应,即可取消线程执行 。
Framework 4.0 提供了两个类CancellationTokenSource和CancellationToken来完成这个模式:
  • CancellationTokenSource定义了Cancel方法 。
  • CancellationToken定义了IsCancellationRequested属性和ThrowIfCancellationRequested方法 。
void 取消令牌(){var cancelSource = new CancellationTokenSource();cancelSource.CancelAfter(3000);var t = new Thread(() => Work(cancelSource.Token));t.Start();t.Join();}void Work(CancellationToken cancelToken){while (true){cancelToken.ThrowIfCancellationRequested();// ...Thread.Sleep(1000);}}四、异步编程模式MSDN文档:https://learn.microsoft.com/zh-cn/dotnet/standard/asynchronous-programming-patterns/
异步编程模型(APM)异步编程模型(Asynchronous Programming Model),提出于.NET Framework 1.x 的时代,基于IAsyncResult接口实现类似BeginXXX和EndXXX的方法 。

经验总结扩展阅读