Click here to Skip to main content
12,079,391 members (26,514 online)
Click here to Skip to main content
Add your own
alternative version

Stats

133.4K views
102 bookmarked
Posted

One use for Overlapped I/O

, 14 Jan 2004 CPOL
Rate this:
Please Sign up or sign in to vote.
How to use overlapped I/O

Introduction

If you’re like me you’ve taken one look at the Microsoft documentation on overlapped I/O and concluded that you don’t really need it. After all, for the vast majority of the applications I’ve had to work on, I/O processing goes something like this:

OpenFile()

While (File.HasData())
{
    ReadData();
    ProcessData();
    WriteData();
}

CloseFile()

Typically you don’t need to setup I/O operations to allow processing and reading/writing to overlap. Even if you did you could achieve similar results using multithreading. So why did Microsoft provide overlapping I/O? Well here’s one use for it.

Details

Let’s use named pipes instead of real files for our I/O. Let’s further assume we’re writing a server application, which will handle one or more instances of a named pipe. (See Conclusions below for why I used a named pipe in this example).

This is one (greatly simplified and not error checked) way to write the loop. I’m assuming a global BOOL variable called gbl_bStop initially set to FALSE.

while (!gbl_bStop)
{
    HANDLE h = CreateNamedPipe();

    if (ConnectNamedPipe(h))
        _beginthread(threadProc, 0, h);
}

This loop runs until gbl_bStop is set to TRUE. It creates a named pipe and then sits inside the ConnectNamedPipe() call waiting for a client to connect. When a client connects the ConnectNamedPipe() call returns and a new thread is launched to handle this particular client/server connection. The handle returned in the CreateNamedPipe() call is passed to the thread procedure, which will presumably use the handle for read or write operations.

Typically the above loop would be running in its own thread so that your application can handle other events.

This code works fine until you want to stop the server. The main thread sets gbl_bStop to TRUE and waits in vain for the thread to terminate. The problem is that very little of the threads time is spent executing code over which you have any control. Most of the time it’s sitting inside that ConnectNamedPipe() call, deep inside the Operating System, waiting for client connections.

Aha, we can work around that. Let’s set gbl_bStop to TRUE and then make a connection (from our main thread) to the named pipe. Well that will work but it also starts up yet another thread. Ok, we can work around that by checking gbl_bStop when we come out of the ConnectNamedPipe() call to see if we should continue or exit.

Now our loop looks like this:

while (!gbl_bStop)
{
    HANDLE h = CreateNamedPipe();

    if (ConnectNamedPipe(h) && !gbl_bStop)
        _beginthread(threadProc, 0, h);
}

Not much added code but don’t forget our shutdown routine also has to create a connection to the named pipe. It’s getting somewhat complex, with code needed to shut down our application scattered all over the place.

Overlapped I/O usage

This is where overlapped I/O comes in. Let’s write our loop like this instead. I’m assuming a global EVENT object called gbl_hStopEvent and I’m still leaving out a lot of detail.

OVERLAPPED  op;
HANDLE      h,
            handleArray[2];
BOOL        bStop = FALSE;
		
memset(&op, 0, sizeof(op));
handleArray[0] = op.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
handleArray[1] = gbl_hStopEvent;
		
while (bStop == FALSE)
{
    h = CreateNamedPipe(FILE_FLAG_OVERLAPPED);

    ConnectNamedPipe(h, &op);
				
    switch (WaitForMultipleObjects(2, handleArray, FALSE, INFINITE))
    {
    case WAIT_OBJECT_0:
        _beginthread(threadProc, 0, h);
        ResetEvent(handleArray[0]);
        break;

    case WAIT_OBJECT_0 + 1:
        CloseHandle(h);
        bStop = TRUE;
        break;
    }
}

CloseHandle(handleArray[0]);

The key to this is the WaitForMultipleObjects(). We create an array containing a handle to the global stop event and a handle to a local event. The local event handle is also used in the OVERLAPPED structure. We create the named pipe using overlapped I/O and then call ConnectNamedPipe(). However, because we specified overlapped I/O the Operating System returns control to us immediately and we fall into the WaitForMultipleObjects() call. If a client connects to the named pipe the OS will signal the event handle we passed in the OVERLAPPED structure and the code for WAIT_OBJECT_0 is executed. If, on the other hand, our main thread signals gbl_hStopEvent the code for WAIT_OBJECT_0 + 1 is executed and we will exit the loop entirely.

The same technique can be used for the thread procedure using the named pipe connection and for the client side code.

Conclusions

I chose named pipes for this example for simplicity (the examples require fewer lines of code compared to a socket example). But the choice of something other than a regular file on the disk was deliberate. When reading a disk file you're working with a known and predictable entity. On the large time scale (the time scale humans experience) a read from a disk file takes very little time and it's easy to determine when the operation has reached the end (end of file). Thus the pseudocode I showed at the start of the article is reasonable. But when dealing with interprocess communications across (possibly) network connections it's not possible to determine with any kind of accuracy just when the operation might end.

An obvious (and wrong) solution might be to write a tight loop polling the named pipe for new data. But, given the asynchronous nature of a named pipe data conduit you run a risk of wasting an awful lot of CPU cycles executing that tight loop.

Overlapped I/O provides an easy way to ensure your application is always responsive to user input without consuming excessive amounts of CPU time. Code that doesn't run costs the least in performance.

History

  • 19 December 2002 - First version.

  • 15 January 2004 - Added some comments about why Named Pipes were used in the pseudocode.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Rob Manderson
United States United States
I've been programming for 35 years - started in machine language on the National Semiconductor SC/MP chip, moved via the 8080 to the Z80 - graduated through HP Rocky Mountain Basic and HPL - then to C and C++ and now C#.

I used (30 or so years ago when I worked for Hewlett Packard) to repair HP Oscilloscopes and Spectrum Analysers - for a while there I was the one repairing DC to daylight SpecAns in the Asia Pacific area.

Afterward I was the fourth team member added to the Australia Post EPOS project at Unisys Australia. We grew to become an A$400 million project. I wrote a few device drivers for the project under Microsoft OS/2 v 1.3 - did hardware qualification and was part of the rollout team dealing directly with the customer.

Born and bred in Melbourne Australia, now living in Scottsdale Arizona USA, became a US Citizen on September 29th, 2006.

I work for a medical insurance broker, learning how to create ASP.NET websites in VB.Net and C#. It's all good.

Oh, I'm also a Kentucky Colonel. http://www.kycolonels.org

You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 5 Pin
AndyLau00429-Aug-13 19:14
memberAndyLau00429-Aug-13 19:14 
GeneralThanks! Pin
Duojiao Yan8-Dec-11 21:44
memberDuojiao Yan8-Dec-11 21:44 
GeneralHere's another way... Pin
Paul Sanders (AlpineSoft)2-Mar-08 8:21
memberPaul Sanders (AlpineSoft)2-Mar-08 8:21 
GeneralRe: Here's another way... Pin
jjshean20-Nov-09 10:21
memberjjshean20-Nov-09 10:21 
Questionwhich windows versions support it ?? Pin
pratibhap6-Feb-08 2:49
memberpratibhap6-Feb-08 2:49 
AnswerRe: which windows versions support it ?? Pin
Rob Manderson6-Feb-08 4:46
protectorRob Manderson6-Feb-08 4:46 
GeneralGood paper around a bad desing Pin
darbal20-Jan-04 3:21
memberdarbal20-Jan-04 3:21 
GeneralRe: Good paper around a bad desing Pin
edsela20-Jan-04 4:32
memberedsela20-Jan-04 4:32 
GeneralRe: Good paper around a bad desing Pin
armentage21-Jan-04 8:10
memberarmentage21-Jan-04 8:10 
GeneralExcellent ! But i have some problems. Pin
guit444-May-03 23:00
memberguit444-May-03 23:00 
GeneralRe: Excellent ! But i have some problems. Pin
ignacio14-Feb-05 11:25
memberignacio14-Feb-05 11:25 
Generalalso for sockets Pin
Forogar2-Apr-03 4:34
memberForogar2-Apr-03 4:34 
GeneralThanks very much Pin
Paul Farry17-Mar-03 13:10
memberPaul Farry17-Mar-03 13:10 
GeneralRe: Thanks very much Pin
Rob Manderson17-Mar-03 13:38
memberRob Manderson17-Mar-03 13:38 
GeneralRe: Thanks very much Pin
Paul Farry17-Mar-03 19:55
memberPaul Farry17-Mar-03 19:55 
GeneralHelped Me Pin
Renjith R23-Jan-03 8:37
memberRenjith R23-Jan-03 8:37 
Generala good read... Pin
adrian cooper20-Dec-02 6:14
memberadrian cooper20-Dec-02 6:14 
GeneralNice Pin
Giles19-Dec-02 23:58
memberGiles19-Dec-02 23:58 
GeneralFinally.. Overlapped I/O explained Pin
Jubjub19-Dec-02 13:48
memberJubjub19-Dec-02 13:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160212.1 | Last Updated 15 Jan 2004
Article Copyright 2002 by Rob Manderson
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid