The IO Completion Port

An I/O Completion Port is a mechanism to deal with asynchronous file I/O. It achieves this by managing a small number of threads in an efficient manner. It is possible to extend the usage of I/O Completion Ports to ignore file operations and utilise the ability to manage threads efficiently. This subject IO Completion Port is typically a chapter of a book.

All this is achieved with 3 procedures

CreateIoCompletionPort()
GetQueuedCompletionStatus()
PostQueuedCompletionstatus()

CreateIoCompletionPort() performs 2 functions

The above operations are done typically during the process initialisation

CreateIoCompletionPort() // Create Port and specify number of threads (n)
CreateIoCompletionPort() // Associate a file with port - Optional
Createthreads() // (n) identical threads

Now the main cycle of the worker threads begins and each uses GetQueuedCompletionStatus() which will only return when a file operation completes. The worker threads (all identical) have the following structure.

While(1){
GetQueuedCompletionStatus(); // wait for completion of an IO
Process What ever has completed ();
Start another file operation();
}

That is it, all the rest such as how many threads, how threads enter the queues LIFO are either implementation details or too technical at this stage of learning and can come later.

Note. any one who is used to asynchronous operation will find the main loop interesting as normal asynchronous programming is as below

Start Read or Write Overlapped IO()
Do something else()
Wait on file object() // or alert mechanism

I always had trouble finding something else to do. The IO completion is simple and elegant and "Process What ever has completed" makes more sense than do something else.

Yes there is something missing, between the initialisation section and the main loop some operation must be started otherwise GetQueuedCompletionStatus() can never return. This can be done by starting the first file operation before the main loop.

Let us now use an IO port with no IO, we will use the property that IO Ports schedule their threads efficiently.

CreateIoCompletionPort() // Create Port and specify number of threads (say 8 threads)
// Do not Associate a file with the port
Createthreads() // (8) identical threads
PostQueuedCompletionstatus() // send 8 completion messages, that is we simulate completed file IO

Now the main cycle of the worker threads begins and each uses GetQueuedCompletionStatus() which will only return when it receives a IO COMPLETION OR AS IN THIS CASE A PostQueuedCompletionstatus() message.

While(1){
GetQueuedCompletionStatus(); // wait for message
This threads job();
PostQueuedCompletionstatus(); // throw in another completion message - ad infintum
}

What have I missed, a lot

IO Completion Ports are a lot simpler than they first appear, a good article in C/C++ Users Journal April 1998, General-purpose Threads with I/O Completion ports, Kevin T. Manley wraps the above function calls in C++ classes to provide easy to use interfaces.

Summary

 

CreateIoCompletionPort creates port and attaches file, socket etc
Create identical threads, this is a bit obvious, but I like to stress it
GetQueuedCompletionStatus waits for an IO to complete, as above stress, any IO associated with this port.
PostQueuedCompletionstatus allows us too simulate IO completing and use IO ports for other non file IO uses.

 

 

To the Mighty Dwarf's cave

End

E-Mail - Dave Weatherall


@Copyright 2003  by Dwarf .