我懂.Abort()是我读过的关于这个话题的大量文章中的邪恶,所以我目前正在删除我所有的Abort,以便以更干净的方式替换它;在比较了stackoverflow上的用户策略之后,在阅读了MSDN中的"100"之后,这两种策略都说明了一种非常相同的方法——即使用volatile bool方法判断策略,这很好,但我仍然有几个问题....

在这里,我立即意识到,如果您没有一个简单的工作进程,而该进程只是在运行一个循环的压缩代码,那该怎么办呢?例如,对我来说,我的进程是一个后台文件上传器进程,我确实循环遍历每个文件,所以这是很重要的,我当然可以将while (!_shouldStop)加到顶部,它覆盖了我的每个循环迭代,但在它到达下一个循环迭代之前,我还有更多的业务流程发生,我希望这个取消过程快速;不是说我需要在整个Worker函数中每隔4-5行循环一次While循环吗?!

我真的希望有更好的方法,有人能告诉我这是否是正确的[而且是唯一的?]方法,或他们过go 为实现我的目标而使用的策略.

谢谢大家.

进一步阅读:All these SO responses假设工作线程将循环.这对我来说并不舒服.如果这是一个线性但及时的后台操作呢?

推荐答案

不幸的是,可能没有更好的 Select .这取决于你的具体情况.这样做的目的是在安全点优雅地停止线程.这就是为什么Thread.Abort不好的关键所在;因为它不能保证在安全点发生.通过在代码中添加停止机制,可以有效地手动定义安全点.这叫做合作取消.基本上有4种广泛的机制来实现这一点.你可以 Select 一个最适合你的情况.

Poll a stopping flag

您已经提到过这种方法.这是很常见的一个.在算法中的安全点定期判断旗帜,并在收到信号时跳伞.标准方法是将变量标记为volatile.如果那不可能或不方便,那么你可以使用lock.请记住,您不能将局部变量标记为volatile,因此如果lambda表达式通过闭包捕获了它,那么您将不得不求助于另一种方法来创建所需的内存屏障.对于这种方法,没有什么需要说的了.

Use the new cancellation mechanisms in the TPL

这与轮询停止标志类似,只是它使用TPL中的新取消数据 struct .它仍然基于合作取消模式.你需要得到CancellationTokenIsCancellationRequested的定期判断.要请求取消,您可以拨打最初提供 token 的CancellationTokenSourceCancel.使用新的取消机制,你可以做很多事情.你可以阅读更多关于here的文章.

Use wait handles

如果工作线程需要等待特定的时间间隔或在其正常运行期间等待信号,则此方法非常有用.例如,您可以使用Set a ManualResetEvent让线程知道该停止了.您可以使用WaitOne函数测试该事件,该函数返回一个bool,指示该事件是否发出了信号.WaitOne接受一个参数,该参数指定如果事件在该时间段内未发出信号,等待呼叫返回的时间.您可以使用此技术代替Thread.Sleep,同时获得停止指示.如果线程可能需要等待其他WaitHandle个实例,那么它也很有用.您可以在一次通话中拨打WaitHandle.WaitAny等待任何事件(包括停止事件).使用一个事件可能比调用Thread.Interrupt更好,因为您可以更好地控制程序流(Thread.Interrupt会引发异常,因此您必须战略性地放置try-catch个块以执行任何必要的清理).

Specialized scenarios

有几种一次性场景具有非常专门的停止机制.把它们全部列举出来肯定超出了这个答案的范围(别介意这几乎是不可能的).我这里的意思的一个很好的例子是Socket级.如果线程在对SendReceive的调用中被阻塞,那么调用Close将在任何阻塞调用中中断套接字,从而有效地解除阻塞.我相信BCL中还有其他几个领域可以使用类似的技术来解锁线程.

Interrupt the thread via 100

这里的优点是,它很简单,您不必将精力集中在向代码中喷洒任何真正有用的东西上.缺点是,您几乎无法控制算法中的安全点.原因是Thread.Interrupt的工作原理是在一个屏蔽调用中注入一个异常.其中包括Thread.SleepWaitHandle.WaitOneThread.Join等,所以你必须明智地 Select 放置它们的位置.然而,大多数情况下,算法决定它们go 哪里,这通常是好的,尤其是如果算法将大部分时间花在其中一个阻塞调用上.如果您的算法没有使用BCL中的一个阻塞调用,那么这种方法将不适用于您.这里的理论是ThreadInterruptException只由.净等待呼叫,因此安全点为likely.至少您知道,线程不能处于非托管代码中,也不能脱离关键部分,在获取状态下留下悬空的锁.尽管它的侵入性比Thread.Abort小,但我仍然不鼓励使用它,因为不清楚哪个调用会响应它,许多开发人员将不熟悉它的细微差别.

.net相关问答推荐

我的Azure应用服务从哪里获取应用设置?

为什么 .NET 中的 System.Version 定义为 Major.Minor.Build.Revision?

是否有任何为 C# 编写的模糊搜索或字符串相似函数库?

lock() 是否保证按请求的顺序获得?

maxRequestLength 的最大值?

调用委托与方法的性能

String 是原始类型吗?

基于多个字符分隔符拆分字符串

将 C# 编译为本机?

在 C# 中将匿名类型转换为键/值数组?

是否有 Linq 方法可以将单个项目添加到 IEnumerable

等待 Async Void 方法调用以进行单元测试

是否可以在 XP 上运行 .NET 4.5 应用程序?

C# List<> 按 x 然后 y 排序

C# 应用程序中的全局键盘捕获

程序员应该使用 SSIS,如果是,为什么?

.NET 桌面应用程序中的 Settings.settings 与 app.config

如何为 Dapper 查询动态创建参数

Uri.Host 和 Uri.Authority 有什么区别

嵌套捕获组如何在正则表达式中编号?