As soon as we write programs that do something more complex than reading and/or writing to a single input or output stream we are confronted with the need to juggle read and write calls in an often unpredictable order.
The reasonable solution to this is to sit back and let the operating system notify us when something interesting has happened using one of the available I/O multiplexing mechanisms.
select, poll and their extended family
The most commonly available and standardized options are the select and poll system calls. However, these have some warts and have largely been superseded by more efficient and flexible alternatives such as epoll in Linux or kqeue in BSD.
In this week's plenary session we live coded examples using both select and epoll (which is the recommendation we give for assignment use). See the code examples here.
The pragmatic solution: middleware
In practice, modern application code is seldom written directly against these low-level system calls, especially since their availability and to some extent behaviour is not consistent across the most common operating system platforms. Instead, one usually uses some kind of middleware, libraries or frameworks that abstract away these details and present a uniform interface to the application programmer that will Just Work and Do the Right Thing.
The most common examples in this particular space include libevent, libev and libuv. We'll revisit this later in the course.
NB: Do not use such libraries when solving the assignments!