如何强制GetQueuedCompletionStatus()立即返回?

时间:2015-10-03 10:29:41

标签: winapi io-completion-ports

我有手工制作的线程池。线程从完成端口读取并执行其他一些操作。必须结束一个特定的线程。如果它挂起在GetQueuedCompletionStatus()或GetQueuedCompletionStatusEx()上,如何中断等待?

  • 有限超时(100-1000毫秒)和退出变量远非优雅,导致延迟并留作最后的手段。
  • 目标线程中APC内的CancelIo(completionPortHandle)导致ERROR_INVALID_HANDLE
  • CancelSynchronousIo(completionPortHandle)导致ERROR_NOT_FOUND
  • 带有终止​​数据包的PostQueuedCompletionStatus()不允许选择线程。
  • 使用互斥锁的Rough TerminateThread()应该可以正常工作。 (我还没有对它进行测试。)但它在意识形态方面是否合适?
  • 我试图等待特殊事件和完成端口。 WaitForMultipleObjects()立即返回,就好像已通知完成端口一样。 GetQueuedCompletionStatus()显示没有返回任何内容。

我阅读Overlapped I/O: How to wake a thread on a completion port event or a normal event?并搜索了很多内容。

问题本身 - 结束线程的工作 - 可能是设计糟糕的标志,我的所有线程应该是平等的,并且复合到正常的线程池中。在这种情况下,PostQueuedCompletionStatus()方法应该可行。 (虽然我怀疑这种方法很漂亮和简洁,特别是如果线程使用GetQueuedCompletionStatusEx()一次获取多个数据包。)

2 个答案:

答案 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链接。此功能将使目标线程进入警报状态,而无需排队。