Reading pipe asynchronously using ReadFile

Multi tool use
Reading pipe asynchronously using ReadFile
I think I need some clarification on how to read from a named pipe and have it return immediately, data or not. What I am seeing is ReadFile fails, as expected, but GetLastError returns either ERROR_IO_PENDING or ERROR_PIPE_NOT_CONNECTED, and it does this until my surrounding code times out. I get these errors EVEN THOUGH THE DATA HAS IN FACT ARRIVED. I know this by checking my read buffer and seeing what I expect. And the pipe keeps working. I suspect I am not using the overlapped structure correctly, I'm just setting all fields to zero. My code looks like this:
gPipe = CreateFile(gPipename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
pMode = PIPE_READMODE_MESSAGE;
bret = SetNamedPipeHandleState(gPipe, &pMode, NULL, NULL);
OVERLAPPED ol;
memset(&ol, 0, sizeof(OVERLAPPED));
// the following inside a loop that times out after a period
bret = ReadFile(gPipe, &tmostat, sizeof(TMO64STAT), NULL, &ol);
if (bret) break;
err = GetLastError();
// seeing err == ERROR_IO_PENDING or ERROR_PIPE_NOT_CONNECTED
So I can do what I want by ignoring the errors and checking for arrived data, but it troubles me. Any idea why I am getting this behavior?
ERROR_PIPE_NOT_CONNECTED
ReadFile
ERROR_IO_PENDING
ReadFile
1 Answer
1
Windows OVERLAPPED I/O doesn't work like the non-blocking flag on other OSes (For example on Linux, the closest equivalent is aio_*()
API, not FIONBIO
)
aio_*()
FIONBIO
With OVERLAPPED I/O, the operation hasn't failed, it proceeds in the background. But you are never checking on it... you just try again. There's a queue of pending operations, you're always starting new ones, never checking on the old ones.
Fill in the hEvent
field in the OVERLAPPED structure, and use it to detect when the operation completes. Then call GetOverlappedResult()
to get the number of bytes actually transferred.
hEvent
GetOverlappedResult()
Another important note -- the OS owns the OVERLAPPED structure and the buffer until the operation completes, you must take care to make sure these stay valid and not deallocate them or use them for any other operation until you confirm that the first operation completed.
Note that there is an actual non-blocking mode for Win32 pipes, but Microsoft strongly recommends against using it:
The nonblocking-wait mode is supported for compatibility with Microsoft LAN Manager version 2.0. This mode should not be used to achieve overlapped input and output (I/O) with named pipes. Overlapped I/O should be used instead, because it enables time-consuming operations to run in the background after the function returns.
use
hEvent
with GetOverlappedResult
is one from 3 ways. and worst. another way use apc completion with ReadFileEx
. third way - bind hFile
to iocp - or via BindIoCompletionCallback
or (vista+) CreateThreadpoolIo
. or to own handled iocp via CreateIoCompletionPort
– RbMm
Jul 2 at 6:21
hEvent
GetOverlappedResult
ReadFileEx
hFile
BindIoCompletionCallback
CreateThreadpoolIo
CreateIoCompletionPort
@RbMm: If you need to handle dozens of simultaneous connections then sure, a completion port is going to be necessary. But if you have an application where communications is not the main purpose, and you just need a remote interface for checking status, then a completion port is counter-productive. Never introduce threading into a program without a good reason -- the overhead of synchronization will rapidly eat up any performance benefits of completion ports and then some.
– Ben Voigt
Jul 2 at 13:14
@RbMm: I personally am partial to the APC approach, but introducing
ReadFileEx
doesn't answer the question of how to make ReadFile
work.– Ben Voigt
Jul 2 at 13:15
ReadFileEx
ReadFile
even for single pipe -
BindIoCompletionCallback
will be good enough and efficient. APC also good (require alertable wait). why i say that use event completion is worst of 3 variants - at first need create event before every io and close (or reuse) after. at second and main - no additional context. say we got that event is signaled. how we get overlapped pointer from this ? need manually map|bind. when in case apc/iocp we got overlapped back, as context pointer. exactly because this it much more better compare event– RbMm
Jul 2 at 14:08
BindIoCompletionCallback
even for single connection good enough have correct context, etc. but not use global
OVERLAPPED
etc. and even for single pipe - we can have several io in concurent - both read and write data. my personal choice - iocp. sometime apc completion. never event. but this is everyone chooses for themselves– RbMm
Jul 2 at 14:29
OVERLAPPED
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
ERROR_PIPE_NOT_CONNECTED
is error, mean that pipe in bad state andReadFile
complete and fail.ERROR_IO_PENDING
mean thatReadFile
mean that operation begin and not completed yet. you need check data only after it completed. ignoring return value/error and check data is error– RbMm
Jul 2 at 6:16