I need to block until one of my pipes has data to be read.
I have tried WaitForMultipleObjects but it just returns immediately saying that one of the pipes has data. A subsequent ReadFile on the pipe blocks.
I cannot use PeekNamedPipe because I need to block until data is available, and peeking in a loop with sleep would result in a delayed reaction because of the sleep.
This code is cross-platform and everything works great on linux because I can use Select on a set of fifo fd's and then read from the one that is ready when select returns, however there doesn't seem to be any equivalent on windows.
I have seen many people saying you have to use overlapped operations with read/writes, but wouldn't this then require me to loop and try and read every single pipe?
Is there no single blocking operation that will block till one of the pipes has data in it?
I have tried WaitForMultipleObjects but it just returns immediately saying that one of the pipes has data. A subsequent ReadFile on the pipe blocks.
Pipes are not mentioned in MSDN's list of waitable object types, so you can't pass a pipe to any of the WaitFor...()
family of functions.
I have seen many people saying you have to use overlapped operations with read/writes, but wouldn't this then require me to loop and try and read every single pipe?
Overlapped I/O is the solution to your problem.
Create your pipes in overlapped mode. Then you can either:
create an event object via CreateEvent()
and assign it to the OVERLAPPED
structure you use for a given read operation. Then you can issue asynchronous ReadFile/Ex()
operations on multiple pipes and use WaitForMultipleObject()
to wait on the event objects until one of them is signaled. The return value of WaitForMultipleObjects()
will tell you which event was signaled, and by association which pipe has read some data.
use GetQueuedCompletionStatus/Ex()
instead of WaitForMultipleObjects()
, then you can omit the event objects. GetQueuedCompletionStatus/Ex()
will tell you which specific OVERLAPPED
struct(s) have been completed (you can use the hEvent
field to pass around user-defined data, if desired).
This is covered in the MSDN documentation:
Synchronous and Overlapped Pipe I/O
select()
can report multiple completed operations in a single call. However, WaitForMultipleObjects()
and GetQueuedCompletionStatus()
can only report a single completed operation at a time. You would have to call them in a loop to discover if multiple operations have completed. GetQueuedCompletionStatusEx()
, on the other hand, can report multiple completed operations at one time.
Is there no single blocking operation that will block till one of the pipes has data in it?
Yes. See above.
Yes, using overlapped I/O is the best choice. You can bind every pipe handle to an I/O Completion Port (directly via CreateIoCompletionPort()
, or indirectly via BindIoCompletionCallback()
). For asynchronous reading, create a struct inherited from OVERLAPPED
and pass it to ReadFile/Ex()
with a pipe handle. Each read needs its own allocated instance of that struct. Then you can use GetQueuedCompletionStatus()
(or the bound callback) to detect when each read has been completed. You do not need any loops.