关闭时ThreadPool,QueueUserWorkItem和Deadlock

时间:2009-04-01 08:46:53

标签: multithreading delphi delphi-2009 deadlock threadpool

我刚刚实现了一个像这里描述的线程池

Allen Bauer on thread pools

非常简单的实现,工作正常,但我的应用程序不再关闭。似乎两个工作线程(以及另一个线程,我猜是排队线程)卡在函数中

ntdll.ZwRemoveIoCompletion

我记得在QueueUserWorkItem的帮助条目(线程池实现中使用的WinAPI函数)中读过有关IO完成的内容,但我无法理解它。我使用WT_EXECUTELONGFUNCTION作为我的工作线程,因为执行可能需要一段时间,我想创建一个新的工作线程,而不是等待现有的线程完成。分配给工作线程的一些任务执行一些I / O操作。我尝试使用WT_EXECUTEINIOTHREAD,但它似乎没有帮助。

我应该提一下,主线程等待进入临界区,而调用堆栈是

System.Halt0, System.FinalizeUnits, Classes.Finalization, TThread.Destroy,
RtlEnterCriticalSection, RtlpWaitForCriticalSection

任何想法我在这里做错了什么?感谢您的帮助。

3 个答案:

答案 0 :(得分:0)

要确保工作线程关闭,如果等待空IO完成端口,则需要通过某种方式唤醒它们。最简单的方法似乎是向端口发送某种类型的NULL消息 - 然后他们应该将其视为一种有序停止的信号。

答案 1 :(得分:0)

您必须先从关键部分离开,然后才能再次进入。所以问题在于锁定。

在某些帖子中:

EnterCriticalSection(SomeCriticalSection);
sort code...
LeaveCriticalSection(SomeCriticalSection);

在其他一些帖子中:

EnterCriticalSection(SomeCriticalSection);
clean up code...
LeaveCriticalSection(SomeCriticalSection);

如果排序代码在第一个线程中运行而第二个线程尝试运行清理代码,则第二个线程将等到排序代码完成并离开临界区。只有在离开临界区后,您才能进入相同的临界区。我希望这可以帮助您缩小死锁代码,因为它位于一个关键部分。

要获得完成端口句柄,您可以在创建完成端口时保存它的句柄:

FIoCPHandle := CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0 , 0, FNumberOfConcurrentThreads);

答案 2 :(得分:0)

使用QueueUserWorkItem时,只要工作线程已经返回到线程池,您就不必做任何事情来关闭它们。线程池的WT_EXECUTEDEFAULT组件将工作项排队到I / O完成端口。此端口是线程池内部实现的一部分,无法访问。

您是否可以为看似卡住的线程提供更详细的调用堆栈?它会使这个问题更容易诊断。