ptg10805159
Section 14.4 I/O Multiplexing 501
network connection is disconnected by thetelnetddaemon), then the child terminates
and the parent is notified by theSIGCHLDsignal. But if the parent terminates (the user
enters an end-of-file character at the terminal), then the parent has to tell the child to
stop. Wecan use a signal for this (SIGUSR1,for example), but it does complicate the
program somewhat.
Instead of two processes, we could use two threads in a single process. This avoids
the termination complexity,but requires that we deal with synchronization between the
threads, which could add morecomplexity than it saves.
We could use nonblocking I/O in a single process by setting both descriptors to be
nonblocking and issuing areadon the first descriptor.Ifdata is present, we read it and
process it. If thereis no data to read, the call returns immediately.Wethen do the same
thing with the second descriptor.After this, we wait for some amount of time (a few
seconds, perhaps) and then try to read from the first descriptor again. This type of loop
is calledpolling.The problem is that it wastes CPU time. Most of the time, therewon’t
be data to read, so we waste time performing thereadsystem calls. We also have to
guess how long to wait each time around the loop. Although it works on any system
that supports nonblocking I/O, polling should be avoided on a multitasking system.
Another technique is calledasynchronous I/O.With this technique, we tell the kernel
to notify us with a signal when a descriptor is ready for I/O. Thereare two problems
with this approach. First, although systems provide their own limited forms of
asynchronous I/O, POSIX chose to standardize a different set of interfaces, so
portability can be an issue. (In the past, POSIX asynchronous I/O was an optional
facility in the Single UNIX Specification, but these interfaces arerequired as of SUSv4.)
System V provides theSIGPOLLsignal to support a limited form of asynchronous I/O,
but this signal works only if the descriptor refers to a STREAMS device. BSD has a
similar signal,SIGIO,but it has similar limitations: it works only on descriptors that
refer to terminal devices or networks.
The second problem with this technique is that the limited forms use only one
signal per process (SIGPOLLorSIGIO). If we enable this signal for two descriptors (in
the example we’ve been talking about, reading from two descriptors), the occurrence of
the signal doesn’t tell us which descriptor is ready.Although the POSIX.1
asynchronous I/O interfaces allow us to select which signal to use for notification, the
number of signals we can use is still far less than the number of possible open file
descriptors. Todetermine which descriptor is ready, we would need to set each file
descriptor to nonblocking mode and try the descriptors in sequence. We discuss
asynchronous I/O in Section 14.5.
Abetter technique is to useI/O multiplexing.To do this, we build a list of the
descriptors that we areinterested in (usually morethan one descriptor) and call a
function that doesn’t return until one of the descriptors is ready for I/O. Three
functions —poll,pselect,andselect—allow us to perform I/O multiplexing. On
return from these functions, we aretold which descriptors areready for I/O.
POSIX specifies that<sys/select.h>be included to pull the information forselectinto
your program. Older systems requirethat you include<sys/types.h>,<sys/time.h>,
and<unistd.h>.Check theselectmanual page to see what your system supports.