有关.NET中干净地终止线程问题 [英] Question about terminating a thread cleanly in .NET

查看:139
本文介绍了有关.NET中干净地终止线程问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我所知Thread.Abort的()是由众多的我读过关于该主题的文章邪,所以我目前在剥开的过程中我中止的,以取代它一个更清洁的方式;和这里的人们在计算器和比较用户的策略后,再经过读如何创建和终止线程(C#编程指南)从MSDN这两种状态的方法大同小异 - 这是使用挥发性布尔办法检查的策略,这是很好的,但我还是有几个问题....

I understand Thread.Abort() is evil from the multitude of articles I've read on the topic, so I'm currently in the process of ripping out to of my abort's in order to replace it for a cleaner way; and after comparing user strategies from people here on stackoverflow and then after reading "How to: Create and Terminate Threads (C# Programming Guide)" from MSDN both which state an approach very much the same -- which is to use a volatile bool approach checking strategy, which is nice, but I still have a few questions....

什么马上站出来为我在这里,是什么,如果你没有这是刚刚运行捣弄code的循环简单的工作进程?比如对我来说,我的过程是一个后台文件上传过程中,我其实遍历每个文件,所以这东西,相信我可以加我的而(!_shouldStop)在涵盖我每次循环,但我有它击中它的下一个循环周期,我想这个取消过程是瞬间之前发生的更多的业务流程上;不要告诉我,我需要撒这些while循环,每4-5线向下贯穿我的整个工作人员的功能?!

Immediately what stands out to me here, is what if you do not have a simple worker process which is just running a loop of crunching code? For instance for me, my process is a background file uploader process, I do in fact loop through each file, so that's something, and sure I could add my while (!_shouldStop) at the top which covers me every loop iteration, but I have many more business processes which occur before it hits it's next loop iteration, I want this cancel procedure to be snappy; don't tell me I need to sprinkle these while loops every 4-5 lines down throughout my entire worker function?!

我真的希望有一个更好的办法,可能有人请告诉我。如果这是事实,正确的[只有?]的方法来做到这一点,或者他们已经在过去使用战略,以实现我以后有什么

I really hope there is a better way, could somebody please advise me on if this is in fact, the correct [and only?] approach to do this, or strategies they have used in the past to achieve what I am after.

由于团伙。

延伸阅读:所有这些所谓的响应承担辅助线程将循环。这不舒服与我小坐。如果它是一个线性的,但及时后台操作

Further reading: All these SO responses assume the worker thread will loop. That doesn't sit comfortably with me. What if it is a linear, but timely background operation?

推荐答案

不幸的是有可能不是一个更好的选择。这要看您的具体方案。这样做是为了停止线程正常的安全点。这是原因的症结所在,为什么 Thread.Abort的不好;因为它不保证为发生在安全点。洒在code与制动机构,你得到有效的手工定义安全点。基本上有这样做的4广泛的机制。您可以选择最适合您的情况之一。

Unfortunately there may not be a better option. It really depends on your specific scenario. The idea is to stop the thread gracefully at safe points. That is the crux of the reason why Thread.Abort is not good; because it is not guarenteed to occur at safe points. By sprinkling the code with a stopping mechanism you are effectively manually defining the safe points. There are basically 4 broad mechanisms for doing this. You can choose the one that best fits your situation.

通过了Thread.interrupt 中断线程

Interrupt the thread via Thread.Interrupt

这样做的优点是,它很简单,你没有把重点放在你洒code有什么真正的。缺点是你无法控制的地方,就安全点都在你的算法。究其原因是因为了Thread.interrupt 通过注入里面的罐头BCL阻塞调用的一个例外的作品。这些措施包括 Thread.sleep代码 WaitHandle.WaitOne 的Thread.join 等,所以你必须要聪明在哪里放置它们。然而,大多数的时间算法决定到哪里去,这就是通常罚款反正特别是如果你的算法花费大量的时间在这些阻塞调用之一。如果算法不使用的BCL的阻塞调用之一,则此方法不适合你的工作。这里的理论是, ThreadInterruptException 只能从.NET等待调用生成所以它的可能的在一个安全点。最起码你知道该线程不能在非托管code或摆脱困境的关键部分在获得的状态留锁晃来晃去的。

The advantage here is that it is simple and you do not have to focus on sprinkling your code with anything really. The disadvantage is that you have little control over where the safe points are in your algorithm. The reason is because Thread.Interrupt works by injecting an exception inside one of the canned BCL blocking calls. These include Thread.Sleep, WaitHandle.WaitOne, Thread.Join, etc. So you have to be wise about where you place them. However, most the time the algorithm dictates where they go and that is usually fine anyway especially if your algorithm spends most of its time in one of these blocking calls. If you algorithm does not use one of the blocking calls in the BCL then this method will not work for you. The theory here is that the ThreadInterruptException is only generated from .NET waiting call so it is likely at a safe point. At the very least you know that the thread cannot be in unmanaged code or bail out of a critical section leaving a dangling lock in an acquired state.

民意测验一个停止标志

您已经提到过这种方法。这是一个pretty的常见的一种。使标志进行定期检查在你的算法的安全点,摆脱困境时,得到信号。标准的做法是,以纪念变量挥发性。如果这是不可能或不方便,那么你可以使用锁定。请记住,你不能标记一个局部变量挥发性因此,如果一个lambda EX pression通过一个封闭捕获它,例如,那么你将不得不求助于不同法,用于创建所需要的存储器屏障。没有太多其他的需要说的这个方法。

You have already mentioned this method. This a pretty common one. Make periodic checks of the flag at safe points in your algorithm and bail out when it gets signalled. The standard approach is to mark the variable volatile. If that is not possible or inconvenient then you can use a lock. Remember, you cannot mark a local variable as volatile so if a lambda expression captures it through a closure, for example, then you would have to resort to a different method for creating the memory barrier that is required. There is not a whole lot else that needs to be said for this method.

使用新的撤销机制的TPL

这是类似于轮询停止标志,不同的是它采用了新的抵消数据结构中的第三方物流。它仍然是基于合作消除模式。你需要得到一个的CancellationToken 和定期检查 IsCancellationRequested 。请求取消你会打电话取消 CancellationTokenSource 最初提供的令牌。有很多,你可以用新的机制,取消做。你可以阅读更多有关这里

This is similar to polling a stopping flag except that it uses the new cancellation data structures in the TPL. It is still based on cooperative cancellation patterns. You need to get a CancellationToken and the periodically check IsCancellationRequested. To request cancellation you would call Cancel on the CancellationTokenSource that originally provided the token. There is a lot you can do with the new cancellation mechanisms. You can read more about here.

使用等待句柄

如果您的工作线程需要等待一个特定的时间间隔或用于其正常工作期间的信号这种方法可能是有用的。您可以设置 A 的ManualResetEvent ,例如,让线程知道现在是时候停止。您可以测试使用的WaitOne 函数返回一个布尔表示事件是否已被通知的事件。该的WaitOne 需要一个参数,指定了多少时间来等待调用,如果事件在该时间没有信号返回。您可以代替 Thread.sleep代码的使用这种技术,并获得在同一时间停止指示。它也是有用的,如果有其他的WaitHandle 情况下,该线程可能要等上。您可以拨打 WaitHandle.WaitAny 来等待任何事件(包括停止事件)都在同一个电话。使用事件可能比调用了Thread.interrupt 因为你有更多的控制程序(流的了Thread.interrupt 抛出一个异常,那么你将不得不策略性地将的try-catch 块来执行任何必要的清理)。

This method can be useful if your worker thread requires waiting on an specific interval or for a signal during its normal operation. You can Set a ManualResetEvent, for example, to let the thread know it is time to stop. You can test the event using the WaitOne function which returns a bool indicating whether the event was signalled. The WaitOne takes a parameter that specifies how much time to wait for the call to return if the event was not signaled in that amount of time. You can use this technique in place of Thread.Sleep and get the stopping indication at the same time. It is also useful if there are other WaitHandle instances that the thread may have to wait on. You can call WaitHandle.WaitAny to wait on any event (including the stop event) all in one call. Using an event can be better than calling Thread.Interrupt since you have more control over of the flow of the program (Thread.Interrupt throws an exception so you would have to strategically place the try-catch blocks to perform any necessary cleanup).

专用场景

有几个一次性方案具有非常特殊的停止机制。这肯定是外面这个答案的范围一一列举所有(别介意,这将是几乎是不可能的)。我的意思这里的一个很好的例子是插槽类。如果线程被阻塞在调用发送接收然后调用关闭将中断对任何阻塞套接字调用它有效地疏通了。我相信有在BCL其他几个地方similiar技术可以用来疏通线程。

There are several one-off scenarios that have very specialized stopping mechanisms. It is definitely outside the scope of this answer to enumerate them all (never mind that it would be nearly impossible). A good example of what I mean here is the Socket class. If the thread is blocked on a call to Send or Receive then calling Close will interrupt the socket on whatever blocking call it was in effectively unblocking it. I am sure there are several other areas in the BCL where similiar techniques can be used to unblock a thread.

这篇关于有关.NET中干净地终止线程问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆