Fundamentals 15 min read

Understanding Synchronization, Blocking, and I/O Models in Linux

This article explains the concepts of synchronous vs. asynchronous execution, blocking vs. non‑blocking operations, user and kernel space, process switching, file descriptors, cache I/O, and compares various Linux I/O models such as select, poll, epoll, signal‑driven and asynchronous I/O.

IT Architects Alliance
IT Architects Alliance
IT Architects Alliance
Understanding Synchronization, Blocking, and I/O Models in Linux

It first distinguishes synchronous (a task must wait for its dependent task to finish) from asynchronous (a task proceeds without waiting for the dependent task, receiving only a notification).

Next, it explains blocking (the calling thread is suspended until the operation completes) versus non‑blocking (the function returns immediately with an error if the operation cannot be completed, requiring the caller to poll).

The article then describes the division of a 32‑bit virtual address space into kernel space (the highest 1 GB, 0xC0000000‑0xFFFFFFFF) and user space (the lower 3 GB, 0x00000000‑0xBFFFFFFF) to protect kernel memory.

Process switching is outlined in six steps: saving the CPU context, updating the PCB, moving the PCB to the appropriate queue, selecting another process, updating memory‑management structures, and restoring the saved context.

A file descriptor is defined as a non‑negative integer that indexes the per‑process table of open files maintained by the kernel, primarily used in Unix‑like systems.

The concept of cache I/O is introduced, where data is first copied into the kernel’s page cache before being transferred to user space, noting the overhead of multiple copies.

Various I/O models are then presented: synchronous (blocking), non‑blocking, I/O multiplexing, signal‑driven, and asynchronous. The article notes that signal‑driven I/O is rarely used in practice.

In the blocking I/O model, a call such as recv() blocks the process until data is ready, after which the kernel copies the data to user space and returns success.

Non‑blocking I/O sets a socket to non‑blocking mode, causing the kernel to return an error when the operation cannot be completed immediately, which leads to busy‑waiting and high CPU usage.

I/O multiplexing uses system calls like select , poll , and epoll to monitor multiple sockets; these calls may block the process but only until at least one descriptor becomes ready, reducing unnecessary polling.

Signal‑driven I/O installs a signal handler (e.g., for SIGIO ) so the process continues running and is notified via a signal when the socket is ready, after which normal I/O functions can be called.

Asynchronous I/O (AIO) allows a process to issue aio_read and continue working; the kernel notifies the process when the data is ready. Libraries such as libevent , libev , and libuv provide higher‑level abstractions.

The article compares the five I/O models, emphasizing differences in waiting time and data‑copy phases, and highlights that non‑blocking and asynchronous I/O differ mainly in who performs the active polling.

Finally, it discusses the differences among select , poll , and epoll , including their scalability, level‑triggered versus edge‑triggered behavior, and appropriate usage scenarios.

LinuxSynchronizationepollselectblockingIO modelsprocess switching
IT Architects Alliance
Written by

IT Architects Alliance

Discussion and exchange on system, internet, large‑scale distributed, high‑availability, and high‑performance architectures, as well as big data, machine learning, AI, and architecture adjustments with internet technologies. Includes real‑world large‑scale architecture case studies. Open to architects who have ideas and enjoy sharing.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.