FREE Subscription to Dr. Dobb’s Digest: Same Great Content, New Digital Edition
Site Archive (Complete)
C++
Email
Print
Reprint

add to:
Del.icio.us
Digg
Google
Furl
Slashdot
Y! MyWeb
Blink
August 03, 2007

Multithreaded Asynchronous I/O & I/O Completion Ports

(Page 2 of 4)

Associating File Descriptors with a Port

Once a port has been created, file descriptors opened with the FILE_FLAG_OVERLAPPED (or WSA_FLAG_OVERLAPPED for sockets) may be associated with the port via another call to the same function. To associate an open file descriptor (or socket) with an I/O completion port, the caller passes the descriptor as the first parameter, the handle of the existing completion port as the second parameter, and a value to be used as the "completion key" for the third parameter. The completion key value is passed back when removing completed I/O requests from the port. The fourth parameter is ignored when associating files to completion ports; a good idea is to set this to zero.

Initiating Asynchronous I/O Requests: OVERLAPPED Explained

Once a descriptor is associated with a port, (and you may associate many file descriptors with a single I/O Completion Port), an asynchronous I/O operation on any of the descriptor(s) results in a completion event being posted to the port by the operating system. The same Windows APIs that let callers perform standard synchronous I/O have a provision for issuing asynchronous I/O requests. This is accomplished by passing a valid OVERLAPPED pointer to one of the standard functions. For example, take a look at ReadFile:

BOOL ReadFile( HANDLE File, LPVOID pBuffer, DWORD NumberOfBytesToRead, LPDWORD pNumberOfBytesRead, LPOVERLAPPED pOverlapped );

For typical (synchronous) I/O operations, you've always passed NULL for the last parameter, but when doing asynchronous I/O, you need to pass the address of an OVERLAPPED structure in order to specify certain parameters as well as to receive the results of the operation. Asynchronous calls to ReadFile are likely to return FALSE, but GetLastError returns ERROR_IO_PENDING, indicating to the caller that the operation is expected to complete in the future.

A common mistake when using OVERLAPPED structures is to pass the address of an OVERLAPPED structure declared on the stack:

OVERLAPPED Gone; // Set up 'Gone'.. ReadFile ( hFile, pBuf, Count, &NumRead, &Gone );

This just won't work because ReadFile returns immediately, and when the function containing the call to ReadFile exits, the stack will be unwound and the data pointed to by &Gone will become invalid. Thus, you should ensure that your program manages its OVERLAPPED structures (and any buffers you're using) carefully. The example employs a fairly common strategy that involves having a C++ class representing a connection derive from OVERLAPPED—which may offend some C++ purists, but is a practical solution to the problem. The connections are allocated on the heap, and when I/O operations are initiated, the connections' pointer is passed as the pointer to OVERLAPPED.

Previous Page | 1 Multithreaded Asynchronous I/O | 2 Associating File Descriptors with a Port | 3 Retrieving Completed I/O Events from the Port | 4 A Practical Example: The Fire Web Server Next Page
TOP 5 ARTICLES
No Top Articles.



MICROSITES
FEATURED TOPIC

ADDITIONAL TOPICS

INFO-LINK