aiowait() takes a timeout argument, which indicates how long the caller is willing to wait. As usual, a NULL pointer here means that the caller is willing to wait indefinitely, and a pointer to a structure containing a zero value means that the caller is unwilling to wait at all.
You might start an asynchronous I/O operation, do some work, then call aiowait() to wait for the request to complete. Or you can use SIGIO to be notified, asynchronously, when the operation completes.
Finally, a pending asynchronous I/O operation can be cancelled by calling aiocancel(). This routine is called with the address of the result area as an argument. This result area identifies which operation is being cancelled.
Shared I/O and New I/O System Calls
When multiple threads are performing I/O operations at the same time with the same file descriptor, you might discover that the traditional UNIX I/O interface is not thread safe. The problem occurs with nonsequential I/O. This uses the lseek(2) system call to set the file offset, which is then used in the next read(2) or write(2) call to indicate where in the file the operation should start. When two or more threads are issuing lseeks() to the same file descriptor, a conflict results.
To avoid this conflict, use the pread(2) and pwrite(2) system calls.
#include <sys/types.h> #include <unistd.h> ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset); ssize_t pwrite(int filedes, void *buf, size_t nbyte, off_t offset); |
These behave just like read(2) and write(2) except that they take an additional argument, the file offset. With this argument, you specify the offset without using lseek(2), so multiple threads can use these routines safely for I/O on the same file descriptor.
Alternatives to getc(3C) and putc(3C)
An additional problem occurs with standard I/O. Programmers are accustomed to routines such as getc(3C) and putc(3C) being very quick--they are implemented as macros. Because of this, they can be used within the inner loop of a program with no concerns about efficiency.
However, when they are made thread safe they suddenly become more expensive--they now require (at least) two internal subroutine calls, to lock and unlock a mutex.
To get around this problem, alternative versions of these routines are supplied, getc_unlocked(3S) and putc_unlocked(3C).
These do not acquire locks on a mutex and so are as quick as the original, nonthread-safe versions of getc(3C) and putc(3C).
However, to use them in a thread-safe way, you must explicitly lock and release the mutexes that protect the standard I/O streams, using flockfile(3C) and funlockfile(3C). The calls to these latter routines are placed outside the loop, and the calls to getc_unlocked() or putc_unlocked() are placed inside the loop.