LAssociate a device with a complete port
When creating an I/O completion port, the kernel actually creates five different data structures, as shown in Table 2-1. Please refer to it before continuing reading.
Table 2-1 Internal Working Mechanism of the I/O completed Port
The first data is the device list, indicating one or more devices associated with the completion port. Call createiocompletionport to associate the device with the port. I created my function again, associatedevicewithcompletionport, to encapsulate the call to createiocompletionport.
Bool associatedevicewithcompletionport (
Handle hcompport, handle hdevice, DWORD dwcompkey ){
Handle H = createiocompletionport (hdevice, hcompport, dwcompkey, 0 );
Return (H = hcompport );
}
AssociateDeviceWithCompletionPort: add one to the list of devices with completed ports. During the call, you need to call the existing finished port handle (returned by the previous CreateNewCompletionPort call), the device handle (which can be a file, a SOCKET port, mail slot, pipe, etc ), and the completion key value (meaningful value; the operating system does not care about what is actually passed in) to this function. Each time you associate a device with a port, the system adds the information to the list of devices that have completed the port.
Note:
The CreateIoCompletionPort function is complex. We recommend that you consciously divide the function into two reasons during calling. A complicated advantage is that you can open a file and create a new complete port. For example, the following code opens a file and creates a complete port and associates the file with it. All I/O requests for this file carry the CK_FILE completion key value after completion, and the port allows parallel execution of up to two threads.
# Define CK_FILE 1
HANDLE hfile = CreateFile (...);
HANDLE hCompPort = CreateIoCompletionPort (hfile, NULL, CK_FILE, 2 );
The second data structure is the I/O Completion queue. When the asynchronous I/O Request of the device is complete, the system checks whether the device is associated with the completion port. If yes, the system adds the completed I/O requests to the I/O Completion queue of the completed port. Each queue contains the number of transmitted bytes, the completed key value set when the device is associated with the port, the OVERLAPPED structure pointer of the I/O request, and the error code. We will discuss how to delete a queue later.
Note:
It is possible to generate a device I/O request without adding the item to the queue of the I/O completion port. This is usually not necessary, but it may happen. For example, you can send data through a socket and do not care whether the data is sent or not.
To generate such an I/O request, you must set the hevent Member of the overlapped structure to a valid event handle, and set the highest position to 1 through a bit or operation, as shown below:
Overlapped. hevent = createevent (null, true, false, null );
Overlapped. hevent = (handle) (dword_ptr) overlapped. hevent | 1 );
Readfile (..., & overlapped );
Now you can generate an I/O Request and pass in the overlapped structure address to the required function (for example, the preceding readfile ).
If you do not need to create an event, you can stop the I/O completed queue, for example, the following code. However, it does not work:
Overlapped. hevent = 1;
Readfile (..., & overlapped );
In addition, do not forget to reset the event handle before closing it:
Closehandle (handle) (dword_ptr) overlapped. hevent &~ 1 ));