High-level languages often expose stream-based I/O abstraction to the programmer, where blocking or non-blocking streams offer select/read/write operations. (AFAIK, message-based I/O seems is usually an even higher-level abstraction built on top of streams.)

But at the low level, the communication between the CPU and the hardware devices uses interrupts, programmed (polled) I/O, or DMA.

How can all of them map well into the same stream I/O abstraction that (as far as I can tell) completely hides the difference between these very different low-level models? Are there any cases where a high-level developer who uses stream I/O abstraction should actually be concerned about the difference between interrupt-driven and programmed I/O?

  • Files, sockets, and keyboards are all naturally represented as a (potentially infinite) sequence of bytes. Can you think of an example that's implemented as a stream but can not be represented as a sequence of bytes?
    – kdgregory
    Jan 10 '17 at 19:01
  • @kdgregory yes, all I/O results in a sequence of bytes. But the timing of obtaining those bytes and the resource utilization required to obtain them is very different between polling and interrupts. I expected that a successful I/O abstraction would be unable to completely hide those differences from developers.
    – max
    Jan 10 '17 at 20:48
  • 1
    I would assume the opposite: that a successful abstraction would hide all of the details in the lower levels of the stack. As part of that abstraction, when a higher-level layer asks for the "next byte," the lower level(s) are responsible for putting the process into an IO wait until the next byte is available. It really doesn't matter (in my experience) how that next byte is actually loaded into memory.
    – kdgregory
    Jan 10 '17 at 21:34
  • Perhaps there's a more specific question that you could ask? Otherwise I think you'll end up with answers that mix the various overloaded meanings of the word "stream".
    – kdgregory
    Jan 10 '17 at 21:35

Interrupt based IO does not map to streams well.

One particular example would be a select system call. It provides a way to wait for input on arbitrary count of file descriptors but this API almost never manifests in stream API of high level libraries

Asynchronous IO also does not map to usual streams. This is why role of streams diminishes in modern libraries and gives way to more generic event driven APIs, for example C++ boost::asio, Java NIO. They are more effective for asynchronous and parrallel applications and are a reaction for growing parallelization demand.

Note however, that internally, most of these APIs are still using same system interfaces still based on interrupts and good old buffers. It is possible, because libraries are still hiding details behind layers of abstractions.

BTW, all these abstractions (streams,events,buffered IO) are interchangeable at expense of some performance. For example, streams can be created using events with some blocking queues, backward conversion could be provided by dedicated thread.

  • Can you recommend any books/blogs that discuss this in more depth?
    – max
    Jan 10 '17 at 20:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.