不幸的是,可能没有更好的 Select .这取决于你的具体情况.这样做的目的是在安全点优雅地停止线程.这就是为什么Thread.Abort
不好的关键所在;因为它不能保证在安全点发生.通过在代码中添加停止机制,可以有效地手动定义安全点.这叫做合作取消.基本上有4种广泛的机制来实现这一点.你可以 Select 一个最适合你的情况.
Poll a stopping flag个
您已经提到过这种方法.这是很常见的一个.在算法中的安全点定期判断旗帜,并在收到信号时跳伞.标准方法是将变量标记为volatile
.如果那不可能或不方便,那么你可以使用lock
.请记住,您不能将局部变量标记为volatile
,因此如果lambda表达式通过闭包捕获了它,那么您将不得不求助于另一种方法来创建所需的内存屏障.对于这种方法,没有什么需要说的了.
Use the new cancellation mechanisms in the TPL
这与轮询停止标志类似,只是它使用TPL中的新取消数据 struct .它仍然基于合作取消模式.你需要得到CancellationToken
和IsCancellationRequested
的定期判断.要请求取消,您可以拨打最初提供 token 的CancellationTokenSource
的Cancel
.使用新的取消机制,你可以做很多事情.你可以阅读更多关于here的文章.
Use wait handles
如果工作线程需要等待特定的时间间隔或在其正常运行期间等待信号,则此方法非常有用.例如,您可以使用Set
a ManualResetEvent
让线程知道该停止了.您可以使用WaitOne
函数测试该事件,该函数返回一个bool
,指示该事件是否发出了信号.WaitOne
接受一个参数,该参数指定如果事件在该时间段内未发出信号,等待呼叫返回的时间.您可以使用此技术代替Thread.Sleep
,同时获得停止指示.如果线程可能需要等待其他WaitHandle
个实例,那么它也很有用.您可以在一次通话中拨打WaitHandle.WaitAny
等待任何事件(包括停止事件).使用一个事件可能比调用Thread.Interrupt
更好,因为您可以更好地控制程序流(Thread.Interrupt
会引发异常,因此您必须战略性地放置try-catch
个块以执行任何必要的清理).
Specialized scenarios个
有几种一次性场景具有非常专门的停止机制.把它们全部列举出来肯定超出了这个答案的范围(别介意这几乎是不可能的).我这里的意思的一个很好的例子是Socket
级.如果线程在对Send
或Receive
的调用中被阻塞,那么调用Close
将在任何阻塞调用中中断套接字,从而有效地解除阻塞.我相信BCL中还有其他几个领域可以使用类似的技术来解锁线程.
Interrupt the thread via 100
这里的优点是,它很简单,您不必将精力集中在向代码中喷洒任何真正有用的东西上.缺点是,您几乎无法控制算法中的安全点.原因是Thread.Interrupt
的工作原理是在一个屏蔽调用中注入一个异常.其中包括Thread.Sleep
、WaitHandle.WaitOne
、Thread.Join
等,所以你必须明智地 Select 放置它们的位置.然而,大多数情况下,算法决定它们go 哪里,这通常是好的,尤其是如果算法将大部分时间花在其中一个阻塞调用上.如果您的算法没有使用BCL中的一个阻塞调用,那么这种方法将不适用于您.这里的理论是ThreadInterruptException
只由.净等待呼叫,因此安全点为likely.至少您知道,线程不能处于非托管代码中,也不能脱离关键部分,在获取状态下留下悬空的锁.尽管它的侵入性比Thread.Abort
小,但我仍然不鼓励使用它,因为不清楚哪个调用会响应它,许多开发人员将不熟悉它的细微差别.