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

Winapi 如何强制GetQueuedCompletionStatus()立即返回?,winapi,io-completion-ports,Winapi,Io Completion Ports,我有手工做的线池。线程从完成端口读取数据并执行其他操作。必须结束一个特定的线程。如果它挂起GetQueuedCompletionStatus()或GetQueuedCompletionStatusEx(),如何中断它的等待 有限超时(100-1000毫秒)和退出变量远远不够优雅,会导致延迟,并将其作为最后手段 目标线程中APC内的CancelIo(completionPortHandle)导致错误\u无效\u句柄 CancelSynchronousIo(completionPortHandle

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

  • 有限超时(100-1000毫秒)和退出变量远远不够优雅,会导致延迟,并将其作为最后手段
  • 目标线程中APC内的CancelIo(completionPortHandle)导致
    错误\u无效\u句柄
  • CancelSynchronousIo(completionPortHandle)导致
    错误\u未找到
  • 带有终止数据包的PostQueuedCompletionStatus()不允许选择线程
  • 带有互斥对象的粗糙TerminateThread()应该可以工作。(我没有测试过。)但它在意识形态上好吗
  • 我试图等待特殊事件和完成端口
    WaitForMultipleObjects()
    立即返回,就像发送了完成端口信号一样<代码>GetQueuedCompletionStatus()显示未返回任何内容
我经常阅读和谷歌搜索


也许,问题本身——结束线程的工作——是糟糕设计的标志,我所有的线程都应该是平等的,并组合到正常的线程池中。在这种情况下,PostQueuedCompletionStatus()方法应该可以工作。(尽管我怀疑这种方法是否美观简洁,特别是当线程使用GetQueuedCompletionStatusEx()一次获取多个数据包时。)

如果您只想减小线程池的大小,那么退出哪个线程并不重要

但是,如果出于某种原因,您需要向特定线程发出需要退出的信号,而不是允许任何线程退出,则可以使用此方法

如果您使用
GetQueuedCompletionStatusEx
,您可以通过为
fAlertable
传递
TRUE
来执行可警报的等待。然后,可以使用
QueueUserAPC
将APC排队到要退出的线程

如果线程很忙,那么您仍然必须等待当前工作项完成


当然不要叫TerminateThread

不幸的是,I/O完成端口句柄始终处于信号状态,因此不能真正用于
WaitFor*
函数中

GetQueuedCompletionStatus[Ex]
是在完成端口上进行阻止的唯一方法。对于空队列,只有当线程发出警报时,函数才会返回。正如@Ben所提到的,
QueueUserAPC
将使线程发出警报,并导致
GetQueuedCompletionStatus
返回

但是,
QueueUserAPC
分配内存,因此在内存不足或内存配额有效时可能会失败。
PostQueuedCompletionStatus
也是如此。因此,在退出路径上使用这些函数中的任何一个都不是一个好主意

不幸的是,唯一可靠的方法似乎是调用由
ntdll.dll
导出的未记录的
ntalerthread

extern "C" NTSTATUS __stdcall NtAlertThread(HANDLE hThread);

链接到
ntdll.lib
。此函数将使目标线程进入警报状态,而无需排队。

“Rough TerminateThread”:在终止时,您无法真正知道线程已挂起。所以它是不安全的。为什么你需要选择一个特定的线程?@usr的确,即使我将数据包处理代码和终止调用包装在互斥锁中,刚从队列中取出但尚未开始处理的数据包也可能丢失。@Ben“just don't”是我所说的“思想上”。你的两个建议都有问题。你不想取消IO,你只想线程退出,对吗?最好是在APC内设置一个标志。当GetQueuedCompletionStatusEx返回时,您必须检查返回代码(因为如果有APC,则可能没有任何工作),然后检查标志以查看是否必须退出。啊,我忘了说事件。我会更新并回答。简而言之,
WaitForMultipleObjects
立即返回,就好像完成端口发出了信号,但GetQueuedCompletionStatus()没有返回任何内容。我试图执行空APC,结果导致等待返回!我仍然不知道这是对还是错,但似乎还可以。我已经多次阅读了fAlertable的TRUE value是什么意思的语句:当系统将I/O完成例程或APC排队给线程时,线程返回,线程执行该函数。谢谢。是的,没错。一个可报警的等待将执行APC,然后返回,无论IO完成是否可用。