我有手工制作的线程池。线程从完成端口读取并执行其他一些操作。必须结束一个特定的线程。如果它挂起在GetQueuedCompletionStatus()或GetQueuedCompletionStatusEx()上,如何中断等待?
ERROR_INVALID_HANDLE
。ERROR_NOT_FOUND
。WaitForMultipleObjects()
立即返回,就好像已通知完成端口一样。 GetQueuedCompletionStatus()
显示没有返回任何内容。我阅读Overlapped I/O: How to wake a thread on a completion port event or a normal event?并搜索了很多内容。
问题本身 - 结束线程的工作 - 可能是设计糟糕的标志,我的所有线程应该是平等的,并且复合到正常的线程池中。在这种情况下,PostQueuedCompletionStatus()方法应该可行。 (虽然我怀疑这种方法很漂亮和简洁,特别是如果线程使用GetQueuedCompletionStatusEx()一次获取多个数据包。)
答案 0 :(得分:2)
如果您只想减小线程池的大小,那么哪个线程退出并不重要。
但是,如果出于某种原因需要向特定线程发出需要退出的信号,而不是允许任何线程退出,则可以使用此方法。
如果您使用GetQueuedCompletionStatusEx
,则可以通过TRUE
传递fAlertable
来进行警报等待。然后,您可以使用QueueUserAPC
将APC排队到要退出的线程。
如果线程忙,那么您仍然需要等待当前工作项完成。
当然不要调用TerminateThread。
答案 1 :(得分:1)
不幸的是,I / O完成端口句柄始终处于信号状态,因此不能真正用于WaitFor*
函数中。
GetQueuedCompletionStatus[Ex]
是在完成端口上进行阻止的唯一方法。如果队列为空,则仅当线程处于警报状态时,该函数才会返回。如@Ben所述,QueueUserAPC
将使线程处于警报状态并导致GetQueuedCompletionStatus
返回。
但是,QueueUserAPC
分配内存,因此在内存不足的情况下或有效的内存配额下可能会失败。 PostQueuedCompletionStatus
也是如此。因此,在退出路径上使用这些功能中的任何一个都不是一个好主意。
不幸的是,唯一健壮的方法似乎是调用NtAlertThread
导出的未记录的ntdll.dll
。
extern "C" NTSTATUS __stdcall NtAlertThread(HANDLE hThread);
与ntdll.lib
链接。此功能将使目标线程进入警报状态,而无需排队。