Retrieving Completed I/O Events from the Port
Now that we know how to create a completion port, associate descriptors to it, and initiate asynchronous I/O operations on the descriptors, it's on to retrieving completion events from the port. A thread removes an event from the port's queue by calling the GetQueuedCompletionStatus
function:
BOOL GetQueuedCompletionStatus( HANDLE CompletionPort, LPDWORD pNumberOfBytes, PULONG_PTR pCompletionKey, LPOVERLAPPED* ppOverlapped, DWORD Timeout );
Obviously, the first parameter to this function is the handle to the port
object, followed by several pointers and a Timeout
value. Once an operation has completed successfully, the variable pointed to by pNumberOfBytes
contains the number of bytes written or read during the I/O completion, the pCompletionKey
value contains the value of the completion key passed when associating the file descriptor to the port, and the ppOverlapped
variable points to the OVERLAPPED pointer passed as the parameter to the asynchronous I/O function. The timeout
value, which is specified in milliseconds, works just like other Windows functions in that the special value INFINITE may be passed to specify "wait forever."
Sending Your Own Events: PostQueuedCompletionStatus
Before we move on to a practical example, there's one more function to discuss:
BOOL PostQueuedCompletionStatus( HANDLE CompletionPort, DWORD NumberOfBytesTransferred, ULONG_PTR CompletionKey, LPOVERLAPPED pOverlapped );
This function lets you post completion events to the port. Typically, this function is used to send implementation-specific messages to the port. When you post a completion event to a port, one of the threads blocking on the port successfully returns from its call to GetQueuedCompletionStatus
with copies of the parameters as they were posted.
This function is often used to notify worker threads of some global or application-wide event. Along those lines, the sample program presented in this article posts completion events with a special completion key value of COMPLETION_KEY_SHUTDOWN in order to tell the worker threads that the server is shutting down.