If an asynchronous I/O completes synchronously, is the hEvent in the OVERLAPPED structure signaled anyway?


Yes.

When an I/O completes (whether synchronously or asynchronously), the event is signaled and completion status notifications are queued. The Get­Overlapped­Result/Ex function can be used to wait on an I/O that has already completed; it will merely return immediately. If you ask Has­Overlapped­Io­Completed whether the I/O has completed, and the I/O completed synchronously, it will correctly report, "Yeah, of course it completed. Heck, it completed a long time ago!"

In other words, you can logically treat the case of an asynchronous I/O request completing synchronously as if it had completed asynchronously. It just completes asynchronously before you even blinked.

Comments (12)
  1. Terrapin says:

    However, this is not documented to hold wrt. overlapped winsock sockets. Something about layered service providers possibly screwing this up? Or maybe not.. I, for one, have a fail-safe mechanism in my winsock wrapper code that takes care of this eventuality.

  2. Joshua says:

    @Terrapin: If you adopt the UNIX pattern of always using select on synchronous sockets you won't have that problem.

  3. Henke37 says:

    If only the rest of the system let you pretend that asynchronous operations completing synchronously actually finished asynchronously. But no.

  4. alegr1 says:

    @Ian:

    The documentation: "ReadFileEx ignores the OVERLAPPED structure's hEvent member".

    Also, unlike ReadFile/WriteFile, the function doesn't return FALSE, if I/O is pending.

    Not sure what value you found in ReadFileEx, other than ability to overcome a limit on number of handles in WaitForMultipleObject, which you would not need if you used I/O completion ports instead.

    The design problem was completely self-inflicted.

  5. Ian says:

    @alegr1: Yes, I could have used I/O completion ports, but why use a sledgehammer to crack a nut?

    On your other point, I don't think the documentation ever explicitly states that HasOverlappedIoCompleted() uses the hEvent member.

    Anyway, I posted the above in the hope it might be useful to someone. You don't have to use it yourself.

  6. Joker_vD says:

    @Joshua: select() is actually a quite nice thing. Unfortunately, it has linear complexity AFAIK. But hey, at least select() is one part of POSIX that Windows accurately implements while Linux doesn't!

  7. Joshua says:

    @Joker_vD: Really? Try passing a pipe handle to select() in Windows. It doesn't work.

    AFAIK, the only part of select() on Linux not implemented is local disk asynchronous access, and that only because the local disk drivers themselves don't implement it. This can be a bear on optical media but is otherwise fine.

    True, select() has linear complexity, but it is still the fastest way to do it on a single core. Eventually, you might have to have a few threads doing select() on subsets.

  8. Zan Lynx' says:

    @Joshua:

    I think he's referring to the fact that Linux, in some situations, reports a network file handle ready to read or write but later changes its mind.

    I believe one of these situations happens when a network packet arrives but it later turns out that its checksum was invalid. Another one is when a second thread or process writes into the socket and fills the buffer.

    There are excellent performance and code simplicity reasons for these things but it is true that Linux does not implement a true POSIX select or poll.

  9. Ian says:

    Perhaps only tangentally related to the article, but I've noticed that HasOverlappedIoCompleted() doesn't work on asynchronous I/O begun with ReadFileEx() and WriteFileEx() – it returns TRUE even if the I/O has not completed. This is potentially a problem if you want to test whether the I/O has completed *even if the queued APC hasn't run yet* (because the thread hasn't entered an alertable state).

    I had this problem once because a ReadFileEx() APC needed to call WriteFileEx() if and only if the previous WriteFileEx() had completed, and to drop the message otherwise. But this led to unnecessary dropped messages if the previous ReadFileEx() and WriteFileEx() completed in the 'wrong' order so that the WriteFileEx() APC was second in the queue after the ReadFileEx() APC when the thread entered an alertable state. I solved it by queuing a 'begin write' APC from the ReadFileEx() APC, rather than calling WriteFileEx() directly.

    I still wonder if there was a better way though.

  10. Joker_vD says:

    @Joshua: But select() works with descriptors, right? And files and pipes have handles in Windows, not descriptors — unlike sockets ;)

  11. Richard Cox says:

    @Joker_vD Time to RTFM for select [msdn.microsoft.com/…/ms740141%28v=vs.85%29.aspx]

    "Internally, socket handles in an fd_set structure are not represented as bit flags as in Berkeley Unix. Their data representation is opaque."

    WinSock's select works with handles on Windows.

    However it also does not say anywhere it works for handles that are not sockets. (Much like ReadFile doesn't work for all types of handles either, eg. a process handle).

  12. B. Clay Shannon says:

    For some reason, the question/title makes me think of One Hand Clapping and "If a tree falls in a forest, …."

Comments are closed.

Skip to main content