18

In Java or C# or some other languages, there are non-blocking IO facilities, e.g., for sockets.

So I can give my callback functions to the non-blocking IO and once the non-blocking IO receives anything, it will call my callbacks.

I am wondering how they are implemented. If I create non-blocking IO, behind the scene, does Java or C# just create background threads for them? or the OS underlying has native support for them?

Jack
  • 3,913
  • 8
  • 41
  • 66
  • See the remarks here: http://msdn.microsoft.com/en-us/library/dxkwh6zw.aspx. It appears to use a background thread, which is cached if the same context is re-used. – mellamokb May 10 '12 at 16:50
  • @mellamokb it says an execution context is cached and re-used, it doesn't say anything about a thread. – Chris Shain May 10 '12 at 16:53

1 Answers1

19

On Windows there is underlying OS support for non-blocking I/O, and Microsoft's CLR takes advantage of that. Other CLR implementations (mono) probably do as well, but I don't know for sure. When performing async I/O on the Microsoft CLR there is not a 1-to-1 correlation between pending async I/O operations and threads (or at least managed threads) waiting for those I/O operations to complete.

See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx for some details on the Win32-layer details. Also the information on I/O completion ports here: http://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx

My understanding is this:

  1. I begin an async I/O operation on some application thread.
  2. If it hasn't already, a queue will be created (well, really a kernel-level construct called an I/O completion port, which is associated with a queue in the kernel space of my application). In the .NET world a specially designated thread called an I/O completion port thread will start waiting for notifications of I/O completion on that queue. The important thing to note here is that I can make any number of async I/O requests without increasing the number of I/O completion ports.
  3. The OS will notify the application when I/O completes by enqueueing an I/O completion message on the queue. The I/O completion port thread will then handle that message by invoking the I/O completion callback in my .NET application. In the meantime, if other I/O completes, it's results will be enqueued behind the currently-processing results.

Caveats to the above:

  1. I am sure I got part of this wrong, but I believe the overall gist of it is correct. Eric or someone can come in and correct me where I'm off.

  2. In .NET there are multiple I/O completion port threads. I have no idea how async I/O requests are allocated amongst the various I/O completion ports. This may be an operating system feature (wherein I/O may come back on any port that the application has open).

For Java I am sure it depends on the JVM implementation and the particular OS. I don't know it nearly well enough to speculate beyond that.

EDIT: Historical update, many more details here

Chris Shain
  • 50,833
  • 6
  • 93
  • 125
  • What do you mean `For C# there is underlying OS support...`. The OS has no knowledge that .NET is running on top of it and in theory .NET can run on both Windows and Linux (via mono). – Tudor May 10 '12 at 16:53
  • Please write with more details – Jack May 10 '12 at 16:54
  • There, added some more detail for you Jack. Might be a little off in places but I think that overall my understanding is correct. – Chris Shain May 10 '12 at 17:23