我的同事正在使用第三方.NET库,我们没有源代码。我们使用ThreadPool来让很多线程调用这个库,偶尔会有一个线程永远挂起,而其他线程则兴高采烈地向前推进。
所以我们想使用可怕的Thread.Abort
来杀死这样的线程。我以前在启动自己的线程时也这样做过,但我从来没有使用过ThreadPool。如果我们像这样跟踪每个任务的开始时间:
static Dictionary<Thread, DateTime> started = new Dictionary<Thread, DateTime>();
static void DoSomeWork(object foo)
{
lock(started)
started[Thread.CurrentThread] = DateTime.Now;
SomeBuggyLibraryThatMightInfiniteLoopOrSomething.callSomeFunction(doo);
lock(started)
started.Remove(Thread.CurrentThread);
}
那么我们是否可以锁定和迭代正在运行的线程,并调用Thread.Abort
来杀死它们?如果我们这样做了,那么我们是否需要向ThreadPool添加一个新线程来替换我们刚刚终止的线程,或者ThreadPool会为我们处理这个线程呢?
编辑:我非常清楚Thread.Abort
的所有潜在问题。我知道最好不要在生产代码中使用它,它甚至不一定要停止线程,如果你在线程获得锁的时候中止线程,那么你可以挂起其他线程,等等。但是现在我们的最后期限很紧,我们有充分的理由相信在这个特定的情况下,我们可以在不危及整个进程的情况下调用Thread.Abort
,并且我们希望避免重写这个程序来消除ThreadPool,除非万不得已。
所以我想知道的是:假设我们将在属于ThreadPool的线程上调用Thread.Abort
,这些ThreadPool线程是否会导致任何特殊的问题,我们是否必须手动启动一个新线程来替换被杀死的线程,或者ThreadPool会为我们做这件事?
发布于 2010-02-25 23:40:52
不,你不应该在线程池中的线程上调用Abort。从我的本地测试来看,如果您中止线程,ThreadPool似乎确实会重新创建线程-我中止了1000个线程池线程,但它仍在工作。我不知道你是否应该依赖这种行为,但也许你可以在这种情况下逃脱惩罚。不过,一般来说,使用Thread.Abort并不是实现这一目标的正确方法。
调用你不信任的函数的正确方法是在一个新的进程中启动它,并在必要时终止该进程。
发布于 2010-02-26 00:01:40
不建议使用Thread.Abort,因为它会使您的应用程序处于无效状态。这样做的原因是,当请求线程中止时,可以在第三方库中几乎任何可能的位置引发异常。可能有一些代码段不是为了处理这些异步中止而编写的。
因此,虽然通常不建议中止线程,但有些主机在中止线程时非常激进。其中之一就是ASP.NET,当一个请求耗时太长时,它会为你中止线程。因此,考虑到这一点,说“永远不要中止线程”是愚蠢的。
我建议您找出这段代码挂在哪里( ThreadAbortException的堆栈跟踪应该会给您提供很多信息)。如果它总是挂在同一个地方(可能是死锁),用Reflector找出在这一点上中止线程是否会导致某种状态损坏。有了这些信息,您可能已经可以修复问题(也许您锁定了该库的某个对象),或者可以向该库的作者发送一封邮件。如果所有这些都不起作用,并且您认为中止它没有风险,请务实地将其扼杀:-)
但是,如果有任何状态损坏的变化,您应该尝试遵循Mark Byer的答案。也就是说:尝试在它自己的AppDomain中运行库。通过这种方式,您可以卸载完整的AppDomain,其中的更改不会影响您的应用程序。
发布于 2010-07-09 02:43:07
请阅读斯蒂芬·图布的“'Abortable Thread Pool'
”。他提供了一个可中止线程池的源代码。这是一本有趣的读物。
在线程池排队时,他调用自己的回调'HandleItem‘。在“HandleItem”中,在将当前线程添加到其包装器类中的字典列表之后,他将执行实际的回调。
ThreadPool.QueueUserWorkItem(new WaitCallback(HandleItem));
HandleItem(...) {
...
_threads.Add(item, Thread.CurrentThread);
...
}
他使用字典将他的WorkItems链接到线程,当用户想要取消一个线程时,它会查找并取消那个特定的线程。
Dictionary<WorkItem, Thread>() _threads = New Dictionary<WorkItem, Thread>();
https://stackoverflow.com/questions/2335238
复制相似问题