That's sort-of why I mentioned using poll(), which is often convenient in cases where you want a program to sleep most of the time between doing periodic checks, etc but still to service external events immediately.
Case in point was a system, written in C, I designed that accepted very large quantities of data in the form of device activity logs, transformed them into a common format and loaded them into a data warehouse after manipulating and/or compressing the content of some fields. In the interest of speed, logs were converted into a common format as they arrived. Output from this process was left in memory under the ownership of a log manager process, which owned all logs currently in memory and scheduled their processing. Each log stayed in memory until all field- level processing was complete - the last process in the series loaded to log into the data warehouse and then told the log manager to delete it.
The aims of this approach were to:
- minimise time taken by reading, writing or moving activity logs around
- keep individual processes simple by avoiding multi threading
- allow reuse of some of the field transforming processes by parameterising them
- allow bottlenecks to be eliminated by running multiple copies of any slow process.
As a result, all these processes were based around poll() with the timeout value set non-zero: on timeout they'd look for more work and sleep if there was none: i.e the initial log load&transform process looked for files on the input disk space while everything else asked the log manager for a new logs to work on. That all worked as intended and, last but not least, all processes also included stdin as a file to be monitored by poll() so overall system control and monitoring could be handled by sending messages to stdin on any or all processes.