14.2. Nonblocking I/OIn Section 10.5, we said that the system calls are divided into two categories: the "slow" ones and all the others. The slow system calls are those that can block forever. They include
We also said that system calls related to disk I/O are not considered slow, even though the read or write of a disk file can block the caller temporarily. Nonblocking I/O lets us issue an I/O operation, such as an open, read, or write, and not have it block forever. If the operation cannot be completed, the call returns immediately with an error noting that the operation would have blocked. There are two ways to specify nonblocking I/O for a given descriptor.
ExampleLet's look at an example of nonblocking I/O. The program in Figure 14.1 reads up to 500,000 bytes from the standard input and attempts to write it to the standard output. The standard output is first set nonblocking. The output is in a loop, with the results of each write being printed on the standard error. The function clr_fl is similar to the function set_fl that we showed in Figure 3.11. This new function simply clears one or more of the flag bits. If the standard output is a regular file, we expect the write to be executed once: $ ls -l /etc/termcap print file size -rw-r--r-- 1 root 702559 Feb 23 2002 /etc/termcap $ ./a.out < /etc/termcap > temp.file try a regular file first read 500000 bytes nwrite = 500000, errno = 0 a single write $ ls -l temp.file verify size of output file -rw-rw-r-- 1 sar 500000 Jul 8 04:19 temp.file But if the standard output is a terminal, we expect the write to return a partial count sometimes and an error at other times. This is what we see: $ ./a.out < /etc/termcap 2>stderr.out output to terminal lots of output to terminal ... $ cat stderr.out read 500000 bytes nwrite = 216041, errno = 0 nwrite = -1, errno = 11 1,497 of these errors ... nwrite = 16015, errno = 0 nwrite = -1, errno = 11 1,856 of these errors ... nwrite = 32081, errno = 0 nwrite = -1, errno = 11 1,654 of these errors ... nwrite = 48002, errno = 0 nwrite = -1, errno = 11 1,460 of these errors ... and so on ... nwrite = 7949, errno = 0 On this system, the errno of 11 is EAGAIN. The amount of data accepted by the terminal driver varies from system to system. The results will also vary depending on how you are logged in to the system: on the system console, on a hardwired terminal, on network connection using a pseudo terminal. If you are running a windowing system on your terminal, you are also going through a pseudo-terminal device. Figure 14.1. Large nonblocking write#include "apue.h" #include <errno.h> #include <fcntl.h> char buf[500000]; int main(void) { int ntowrite, nwrite; char *ptr; ntowrite = read(STDIN_FILENO, buf, sizeof(buf)); fprintf(stderr, "read %d bytes\n", ntowrite); set_fl(STDOUT_FILENO, O_NONBLOCK); /* set nonblocking */ ptr = buf; while (ntowrite > 0) { errno = 0; nwrite = write(STDOUT_FILENO, ptr, ntowrite); fprintf(stderr, "nwrite = %d, errno = %d\n", nwrite, errno); if (nwrite > 0) { ptr += nwrite; ntowrite -= nwrite; } } clr_fl(STDOUT_FILENO, O_NONBLOCK); /* clear nonblocking */ exit(0); } In this example, the program issues thousands of write calls, even though only between 10 and 20 are needed to output the data. The rest just return an error. This type of loop, called polling, is a waste of CPU time on a multiuser system. In Section 14.5, we'll see that I/O multiplexing with a nonblocking descriptor is a more efficient way to do this. Sometimes, we can avoid using nonblocking I/O by designing our applications to use multiple threads (see Chapter 11). We can allow individual threads to block in I/O calls if we can continue to make progress in other threads. This can sometimes simplify the design, as we shall see in Chapter 21; sometimes, however, the overhead of synchronization can add more complexity than is saved from using threads. |