I/O Multiplexing

「定义」What we need is the capability to tell the kernel that we want to be notified if one or more I/O conditions are ready (i.e., input is ready to be read, or the descriptor is capable of taking more output). This capability is called I/O multiplexing and is provided by the select and poll functions.

i/o多路复用的使用场景:

  • When a client is handling multiple descriptors (normally interactive input and a network socket), I/O multiplexing should be used.
  • It is possible, but rare, for a client to handle multiple sockets at the same time.
  • If a TCP server handles both a listening socket and its connected sockets, I/O multiplexing is normally used.
  • If a server handles both TCP and UDP, I/O multiplexing is normally used.
  • If a server handles multiple services and perhaps multiple protocols (e.g., the inetd daemon), I/O multiplexing is normally used.

I/O Models

The five I/O models that are available to us under Unix:

  • blocking I/O
  • nonblocking I/O
  • I/O multiplexing (select and poll)
  • signal driven I/O (SIGIO)
  • asynchronous I/O (the POSIX aio_functions)

There are normally two distinct phases for an input operation:

  1. Waiting for the data to be ready
  2. Copying the data from the kernel to the process

For an input operation on a socket, the first step normally involves waiting for data to arrive on the network. When the packet arrives, it is copied into a buffer within the kernel. The second step is copying this data from the kernel’s buffer into our application buffer.

Blocking I/O Model

By default, all sockets are blocking.

In Figure 6.1, the process calls recvfrom and the system call does not return until the datagram arrives and is copied into our application buffer, or an error occurs. The most common error is the system call being interrupted by a signal, as we described in Section 5.9. We say that our process is blocked the entire time from when it calls recvfrom until it returns. When recvfrom returns successfully, our application processes the datagram.

Nonblocking I/O Model

When we set a socket to be nonblocking, we are telling the kernel ‘‘when an I/O operation that I request cannot be completed without putting the process to sleep, do not put the process to sleep, but return an error instead.’’

The first three times that we call recvfrom, there is no data to return, so the kernel immediately returns an error of EWOULDBLOCK instead. The fourth time we call recvfrom, a datagram is ready, it is copied into our application buffer, and recvfrom returns successfully. We then process the data.

When an application sits in a loop calling recvfrom on a nonblocking descriptor like this, it is called polling. The application is continually polling the kernel to see if some operation is ready. This is often a waste of CPU time, but this model is occasionally encountered, normally on systems dedicated to one function.

I/O Multiplexing Model

With I/O multiplexing, we call select or poll and block in one of these two system calls, instead of blocking in the actual I/O system call. 「实际上是将阻塞的那次call转移到了selectpoll.」

We block in a call to select, waiting for the datagram socket to be readable. When select returns that the socket is readable, we then call recvfrom to copy the datagram into our application buffer.

Signal-Driven I/O Model

Refer to UNP chapter 6.2.

Asynchronous I/O Model

In general, these functions work by telling the kernel to start the operation and to notify us when the entire operation (including the copy of the data from the kernel to our buffer) is complete.

This system call returns immediately and our process is not blocked while waiting for the I/O to complete.

Synchronous I/O versus Asynchronous I/O

POSIX defines these two terms as follows: • A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes. • An asynchronous I/O operation does not cause the requesting process to be blocked.

Using these definitions, the first four I/O models—blocking, nonblocking, I/O multiplexing, and signal-driven I/O—are all synchronous because the actual I/O operation (recvfrom) blocks the process. Only the asynchronous I/O model matches the asynchronous I/O definition.

Asio doc says:

  • Synchronous operations are functions that do not return control to the caller until the corresponding operating system operation completes.
  • Asynchronous operations do not block the caller, but instead involve the delivery of a notification to the program when the corresponding operating system operation completes.

see also 同步异步阻塞非阻塞

References

  1. Unix Network Programming, chater 6