Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 正在调用线程。在线程池中的线程上中止_C#_.net_Threadpool - Fatal编程技术网

C# 正在调用线程。在线程池中的线程上中止

C# 正在调用线程。在线程池中的线程上中止,c#,.net,threadpool,C#,.net,Threadpool,我的同事正在使用一个第三方.NET库,我们没有它的源代码。我们使用一个线程池来调用这个库中的许多线程,有时其中一个线程会永远挂起,而其余的线程则会愉快地运行 所以我们想使用可怕的线程.Abort来杀死这样的线程。我以前在旋转我自己的线程时也这样做过,但我从未使用过线程池。如果我们像这样跟踪每个任务的开始时间: static Dictionary<Thread, DateTime> started = new Dictionary<Thread, DateTime>();

我的同事正在使用一个第三方.NET库,我们没有它的源代码。我们使用一个线程池来调用这个库中的许多线程,有时其中一个线程会永远挂起,而其余的线程则会愉快地运行

所以我们想使用可怕的
线程.Abort
来杀死这样的线程。我以前在旋转我自己的线程时也这样做过,但我从未使用过线程池。如果我们像这样跟踪每个任务的开始时间:

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);
}
静态字典已启动=新建字典();
静态void DoSomeWork(对象foo)
{
锁(已启动)
已启动[Thread.CurrentThread]=DateTime.Now;
一些错误的库,可能会无限远地调用某个函数。调用某个函数(doo);
锁(已启动)
已启动。删除(Thread.CurrentThread);
}
然后我们可以锁定并迭代运行中的线程,并调用
Thread.Abort
杀死它们吗?如果我们这样做了,那么我们是否需要向线程池添加一个新线程来替换我们刚刚杀死的线程,或者线程池会为我们处理这个问题

编辑:我非常清楚
Thread.Abort
的所有潜在问题。我知道最好不要在生产代码中使用它,它甚至不一定会停止线程,如果在线程获得锁时中止线程,那么可以挂断其他线程,等等。但是现在我们的截止日期很紧,我们有充分的理由相信在这一特定情况下,我们可以调用
Thread.Abort
,而不会危及整个进程,我们希望避免重写此程序以消除线程池,除非我们必须这样做


所以我想知道的是:假设我们将在属于线程池的线程上调用
Thread.Abort
,这些线程池线程是否会导致任何特殊问题,我们是否必须手动启动一个新线程来替换被终止的线程,或者线程池会为我们这样做?

否,您不应该在线程池中的线程上调用Abort。从我的本地测试来看,如果您中止线程,线程池似乎会重新创建线程——我中止了1000个线程池线程,它仍然在工作。我不知道你是否应该相信这种行为,但在这种情况下,也许你可以逍遥法外。一般来说,尽管使用Thread.Abort不是正确的方法


调用不信任的函数的正确方法是在新进程中启动它,并在必要时终止该进程。

不建议使用Thread.Abort,因为它会使应用程序处于无效状态。这样做的原因是,当要求线程中止时,可以在该第三方库中几乎任何可能的位置引发异常。可能有一些代码段无法编写以处理这些异步中止

因此,虽然通常不建议中止线程,但有些主机在中止线程方面非常激进。其中之一是ASP.NET。当请求花费的时间太长时,它将为您中止线程。所以记住这一点,说“永不中止线程”是愚蠢的

我建议您找出这段代码挂起的位置(ThreadAbortException的堆栈跟踪应该会给您提供很多信息)。如果它总是挂起在同一个位置(可能是死锁),请使用Reflector了解在该点中止线程是否会导致某些状态损坏。有了这些信息,您可能已经解决了问题(可能锁定了该库的某个对象),或者可以向该库的编写者发送邮件。如果这一切都没有帮助,而且你发现中止它没有风险,那么就务实一点,把它扼杀掉:-)


然而,如果有任何国家腐败的变化,你应该尝试按照马克·拜尔斯的答案。即:尝试在其自己的AppDomain中运行该库。通过这种方式,您可以卸载整个AppDomain,并且不会对应用程序产生任何影响。

为了澄清Mark的意思,如果调用Thread.Abort,由于
ThreadAbortException
的特殊性质,您不知道它将在第三方组件中的何处中止—例如,它可能会使
文件流保持打开状态

我会亲自创建IList或队列中引用的线程(因为
ThreadPool
更适合fire and Forget或
WaitHandles
),这取决于您是否认为中止使用第三方组件的线程没有那么危险,
中止它

如果您认为中止可能会使第三方库处于不可接受的状态,那么在使用
System.Threading.Timer

或者

若要坚持使用ThreadPool,您可以改用它。

您还有另一个选择(如果我有空的话,我会选择):


使用reflector对第三方组件进行反向工程,并实际修复阻塞调用以使其异步。

阅读Stephen Toub的
'Abortable Thread Pool'
。 他为可中止的线程池提供源代码。这是一本有趣的书

在线程池排队时,他将自己的回调称为“HandleItem”。在“HandleItem”中,他将当前线程添加到包装器类中的字典列表中,然后执行实际的回调

ThreadPool.QueueUserWorkItem(new WaitCallback(HandleItem));

HandleItem(...) {
...
_threads.Add(item, Thread.CurrentThread);
...
}
他使用字典将他的工作项链接到线程,当用户想要取消某个线程时,它会进行查找并取消该特定线程

Dictionary<WorkItem, Thread>() _threads = New Dictionary<WorkItem, Thread>();
Dictionary()\u threads=newdictionary();

@Eli:您不应该调用线程。也可以在正常线程上中止。首先,Thread.Abort甚至不能保证终止线程。即使它成功地中止了线程,您也不知道留下了什么乱七八糟的东西,或者如何清理它。你可以结束你