Search code examples
c++cwindowsnamed-pipes

What is an overlapped I/O alternative to WaitNamedPipe?


The WaitNamedPipe function allows a pipe client application to synchronously wait for an available connection on a named pipe server. You then call CreateFile to open the pipe as a client. Pseudocode:

// loop works around race condition with WaitNamedPipe and CreateFile
HANDLE hPipe;
while (true) {
    if (WaitNamedPipe says connection is ready) {
        hPipe = CreateFile(...);
        if (hPipe ok or last error is NOT pipe busy) {
            break; // hPipe is valid or last error is set
        }
    } else {
        break; // WaitNamedPipe failed
    }
}

The problem is that these are all blocking, synchronous calls. What is a good way to do this asynchronously? I can't seem to find an API that uses overlapped I/O to do this, for example. For example, for pipe servers the ConnectNamedPipe function provides an lpOverlapped parameters allowing for a server to asynchronously wait for a client. The pipe server can then call WaitForMultipleObjects and wait for the I/O operation to complete, or any other event to be signaled (for example, an event signaling the thread to cancel pending I/O and terminate).

The only way I can think of is to call WaitNamedPipe in a loop with a short, finite timeout and check other signals if it times out. Alternatively, in a loop call CreateFile, check other signals, and then call Sleep with a short delay (or WaitNamedPipe). For example:

HANDLE hPipe;
while (true) {
    hPipe = CreateFile(...);
    if (hPipe not valid and pipe is busy) {
        // sleep 100 milliseconds; alternatively, call WaitNamedPipe with timeout
        Sleep(100);
        // TODO: check other signals here to see if we should abort I/O
    } else
        break;
}

But this method stinks to high heaven in my opinion. If a pipe isn't available for awhile, the thread continues to run - sucking up CPU, using power, requiring memory pages to remain in RAM, etc. In my mind, a thread that relies on Sleep or short timeouts does not perform well and is a sign of sloppy multi-threaded programming.

But what's the alternative in this case?


Solution

  • WaitNamedPipe is completely useless, and will just use all the cpu if you specify a timeout and there's no server waiting for it.

    Just call CreateFile over and over with a Sleep like you're doing, and move it to other threads as you see appropriate. There is no API alternative.

    The only "benefit" WaitNamedPipe provides is if you want to know if you can connect to a named pipe but you explicitly don't want to actually open a connection. It's junk.

    If you really want to be thorough, your only options are

    • Ensure that whatever program is opening the named pipe is always calling CreateNamedPipe again immediately after it's named pipe is connected to.
    • Have your program actually check if that program is running.
    • If your intent is really not to have additional connections, still call CreateNamedPipe, and when someone connects, tell them to go away until they're waited a given amount of time, the close the pipe.