Advising the Linux Kernel on File I/O - Synchronized, Synchronous, and Asynchronous Operations (
Page 3 of 4 )
Unix systems use the terms synchronized, nonsynchronized, synchronous, and asynchronous freely, without much regard to the fact that they are confusing—in English, the differences between “synchronous” and “synchronized” do not amount to much!
A synchronous write operation does not return until the written data is—at least—stored in the kernel’s buffer cache. A synchronous read operation does not return until the read data is stored in the user-space buffer provided by the application. On the other side of the coin, an asynchronous write operation may return before the data even leaves user space; an asynchronous read operation may return before the read data is available. That is, the operations may only be queued for later. Of course, in this case, some mechanism must exist for determining when the operation has actually completed, and with what level of success.
A synchronized operation is more restrictive and safer than a merely synchronous operation. A synchronized write operation flushes the data to disk, ensuring that the on-disk data is always synchronized vis-à-vis the corresponding kernel buffers. A synchronized read operation always returns the most up-to-date copy of the data, presumably from the disk.
In sum, the terms synchronous and asynchronous refer to whether I/O operations wait for some event (e.g., storage of the data) before returning. The terms synchronized and nonsynchronized, meanwhile, specify exactly what event must occur (e.g., writing the data to disk).
Normally, Unix write operations are synchronous and nonsynchronized; read operations are synchronous and synchronized.* For write operations, every combination of these characteristics is possible, as Table 4-1 illustrates.
Table 4-1. Synchronicity of write operations
| Synchronized |
Nonsynchronized |
| Synchronous |
Write operations do not return until the data is flushed to disk. This is the behavior if
O_SYNC
is specified during file open. |
Write operations do not return until the data is stored in kernel buffers. This is the usual behavior. |
| Asynchronous |
Write operations return as soon as the request is queued. Once the write operation ultimately executes, the data is guaranteed to be on disk. |
Write operations return as soon as the request is queued. Once the write operation ultimately executes, the data is guaranteed to at least be stored in kernel buffers. |
Read operations are always synchronized, as reading stale data makes little sense. Such operations can be either synchronous or asynchronous, however, as illustrated in Table 4-2.
Table 4-2. Synchronicity of read operations
| Synchronized |
| Synchronous |
Read operations do not return until the data, which is up-to-date, is stored in the provided buffer (this is the usual behavior). |
| Asynchronous |
Read operations return as soon as the request is queued, but when the read operation ultimately executes, the data returned is up-to-date. |
In Chapter 2, we discussed how to make writes synchronized (via the
O_SYNC
flag), and how to ensure that all I/O is synchronized as of a given point (via
fsync()
and friends). Now, let’s look at what it takes to make reads and writes asynchronous.