Search code examples
winapiio-completion-ports

How to force GetQueuedCompletionStatus() to return immediately?


I have hand-made thread pool. Threads read from completion port and do some other stuff. One particular thread has to be ended. How to interrupt it's waiting if it hangs on GetQueuedCompletionStatus() or GetQueuedCompletionStatusEx()?

  • Finite timeout (100-1000 ms) and exiting variable are far from elegant, cause delays and left as last resort.
  • CancelIo(completionPortHandle) within APC in target thread causes ERROR_INVALID_HANDLE.
  • CancelSynchronousIo(completionPortHandle) causes ERROR_NOT_FOUND.
  • PostQueuedCompletionStatus() with termination packet doesn't allow to choose thread.
  • Rough TerminateThread() with mutex should work. (I haven't tested it.) But is it ideologically good?
  • I tried to wait on special event and completion port. WaitForMultipleObjects() returned immediately as if completion port was signalled. GetQueuedCompletionStatus() shows didn't return anything.

I read Overlapped I/O: How to wake a thread on a completion port event or a normal event? and googled a lot.

Probably, the problem itself – ending thread's work – is sign of bad design and all my threads should be equal and compounded into normal thread pool. In this case, PostQueuedCompletionStatus() approach should work. (Although I have doubts that this approach is beautiful and laconic especially if threads use GetQueuedCompletionStatusEx() to get multiple packets at once.)


Solution

  • If you just want to reduce the size of the thread pool it doesn't matter which thread exits.

    However if for some reason you need to signal to an particular thread that it needs to exit, rather than allowing any thread to exit, you can use this method.

    If you use GetQueuedCompletionStatusEx you can do an alertable wait, by passing TRUE for fAlertable. You can then use QueueUserAPC to queue an APC to the thread you want to quit.

    If the thread is busy then you will still have to wait for the current work item to be completed.

    Certainly don't call TerminateThread.