Skip to content

Archive

Concurrency

172 articles
Software Engineering 19 Sep 2026 6 min read

Fencing Tokens Close the Stale Lease Writer Gap

A distributed lease can expire while its holder is unable to run. The holder may later resume with local state that still says it owns the lease, even though another client has already acquired a newer lease. If the protected storage or service accepts operations solely because the client once acquired the lease, two clients can mutate the same resource across different points in time. A fencing token moves the decisive check from lease ownership into the protected resource. Each successful acquisition receives a token ordered after every earlier token. The resource records the greatest accepted token and rejects operations carrying an older value. The lease still coordinates acquisition, but the token constrains what a delayed former holder can do after it resumes.

Linux 19 Sep 2026 5 min read

eventfd Turns Kernel Notifications into Pollable Counters

A Linux process can signal work through a file descriptor without moving a byte stream between producer and consumer. eventfd() creates a kernel-maintained 64-bit counter whose readiness can be observed by poll(), select(), or epoll. A write adds to the counter; a read consumes its accumulated state according to the descriptor mode. That shape makes eventfd different from a pipe. A pipe preserves a sequence of bytes. An eventfd preserves counter state. When the application needs a wakeup edge plus a compact amount of accumulated state, that distinction removes buffering and framing that a byte stream would otherwise require.

Software Engineering 19 Sep 2026 6 min read

ETag Preconditions Prevent Lost Writes in HTTP Update APIs

Two clients can read the same resource, edit different fields, and send updates seconds apart. If the server accepts both writes without checking which representation each client edited, the later request can silently replace state written by the earlier one. The transport succeeded, yet the application lost a concurrent change. HTTP provides a conditional request mechanism for this boundary. A server can attach an entity tag to a representation, and a client can return that tag in If-Match when submitting a state-changing request. The update proceeds only while the selected representation still satisfies the supplied precondition.

Software Engineering 19 Sep 2026 5 min read

EPOLLET Makes Readiness a State-Transition Contract

A descriptor registered with EPOLLET can remain readable after an event has been delivered without appearing again in the next epoll_wait(). The kernel reports a readiness transition; it does not promise to repeat the same notification merely because unread data remains. That distinction turns edge-triggered epoll into a state-transition contract between the kernel and the event loop. The consequence is structural. A handler cannot treat one event as permission for one read() and then return to the wait loop. With edge-triggered monitoring, the handler must account for all immediately available I/O state before relying on another transition.

Software Engineering 19 Sep 2026 5 min read

Edge-Triggered epoll Requires Draining Readiness to EAGAIN

With EPOLLET, an event loop can consume one notification, read only part of the available data, and then wait indefinitely even though unread bytes remain in the socket buffer. The descriptor is still ready, but no new readiness transition has occurred to generate another edge. That behavior makes edge-triggered epoll a contract between notification semantics and nonblocking I/O. The event says that readiness changed; it is not a promise that the kernel will keep repeating the same notification until the application finishes the work.

Software Engineering 19 Sep 2026 7 min read

Deadline Propagation Bounds Request Lifetime Across Service Calls

A request can stop being useful before every process handling it stops working. An HTTP client may give up after two seconds while an upstream service continues a database query, an RPC, and a retry sequence for several more seconds. Those operations still consume connections, CPU time, queue capacity, and downstream concurrency even though their result no longer has a recipient. A deadline makes that usefulness boundary explicit. Propagating it through nested calls gives participating components a common upper bound derived from the original request. This differs from assigning an independent timeout at every hop: local timeouts limit individual operations, while a propagated deadline limits the lifetime of the operation graph.

Software Engineering 19 Sep 2026 7 min read

Circuit Breakers Bound Failure Traffic Across Service Calls

A circuit breaker changes the admission decision for an outbound call before the dependency receives it. In the closed state, calls proceed and their outcomes feed a failure policy. Once that policy trips, the breaker enters the open state and rejects subsequent calls locally. After a configured recovery interval, a limited set of probe calls can test whether the dependency is usable again. That mechanism is distinct from retries. A retry issues another attempt after a failed attempt. A breaker can prevent an attempt from being issued at all. Combining the two without a precise ordering can amplify traffic during an outage or keep a breaker open based on signals that do not represent dependency health.

Tech 19 Sep 2026 5 min read

Cache-Line False Sharing Moves Coherence Ownership Between CPUs

Cache-Line False Sharing Moves Coherence Ownership Between CPUs Two threads can update different variables without sharing a lock or touching the same bytes and still interfere at the hardware level. If those variables occupy the same cache line, a coherent multiprocessor treats their storage as one coherence unit. Repeated writes from different CPUs can therefore move ownership of that line between caches even though the program considers the variables independent.

Software Engineering 19 Sep 2026 6 min read

Bounded Queues Turn Overload into an Explicit Admission Decision

A queue between a producer and a slower consumer can absorb a temporary rate mismatch. It cannot remove that mismatch. If arrivals continue faster than completions, every accepted item adds to outstanding work. An unbounded queue lets that state accumulate until some other resource becomes the effective limit, often memory or an external timeout. A bounded queue moves the limit into the interface itself. Once capacity is exhausted, admission has to produce an observable result: wait for space, reject new work, discard selected work, or redirect it elsewhere. The queue therefore becomes more than a storage structure. Its capacity and full-queue behavior define part of the system’s overload contract.

Software Engineering 18 Sep 2026 4 min read

timerfd Turns Timer Expiration Counts into Pollable Descriptor State

A Linux timerfd becomes readable when its configured timer has expired. The bytes returned by read(2) are not a timestamp or event record: they encode one unsigned 64-bit integer containing the number of expirations since the previous successful read. Timer state therefore participates in the same readiness machinery as sockets and pipes while retaining timer-specific semantics behind the descriptor boundary. Readiness represents a pending expiration count timerfd_create(2) creates a descriptor associated with a clock, while timerfd_settime(2) arms or disarms its timer. Once at least one expiration is pending, poll(2), select(2), and epoll(7) can report the descriptor as readable.

Software Engineering 18 Sep 2026 5 min read

SO_REUSEPORT Moves Listener Distribution into Socket Selection

SO_REUSEPORT permits multiple Linux AF_INET or AF_INET6 sockets to bind the same local address and port when every member satisfies the reuse-port rules. For TCP listeners, this moves incoming connection distribution ahead of accept(): the kernel selects a listener from the reuse-port group, and that listener receives the connection on its accept queue. For UDP, selection determines which socket receives an incoming datagram. This is a different concurrency boundary from several threads sharing one listening file description. Each reuse-port member is a distinct socket, with its own descriptor, queues, polling state, and lifecycle.

Software Engineering 18 Sep 2026 3 min read

signalfd Routes Pending Signals Through Descriptor I/O

A Linux signalfd becomes readable when a signal selected by its mask is pending for the reading context. A successful read(2) consumes pending signal state and returns one or more fixed-size signalfd_siginfo records. Signal handling can therefore enter a descriptor-driven event loop without turning asynchronous handlers into the primary dispatch mechanism. The descriptor mask does not block signals The mask passed to signalfd(2) selects signals that the descriptor can accept. It does not modify the calling thread’s signal mask. Normal use separately blocks those signals with sigprocmask(2) or pthread_sigmask(3) so their ordinary dispositions do not run before descriptor consumption.

Software Engineering 18 Sep 2026 4 min read

pidfds Bind Process Operations to Stable Kernel References

A numeric PID names a process only while that PID remains assigned to it. After termination and reaping, Linux can reuse the number for another process. A PID file descriptor, or pidfd, instead holds a kernel reference to a specific task, so later operations can target that task without resolving its numeric PID again. This distinction removes a class of time-of-check/time-of-use races from process management. It does not make a process immortal, grant extra permissions, or turn every process operation into a portable descriptor API.

Linux 18 Sep 2026 6 min read

membarrier Moves Memory-Ordering Cost to an Infrequent Coordination Path

A full hardware memory barrier in a frequently executed path can impose a cost on every operation, even when cross-thread coordination happens only occasionally. Linux membarrier() supports a different placement of that cost: a rare coordination path can request an ordering event across a defined set of threads while a frequent path may need only compiler-level ordering. This is not a general replacement for atomics, locks, or the memory model of a programming language. It is a Linux-specific synchronization primitive for designs whose correctness already has a precise pairing between a frequent path and an infrequent coordination path.

Software Engineering 18 Sep 2026 5 min read

Linux eventfd Represents Counter State Through Descriptor Readiness

An eventfd object stores an unsigned 64-bit counter in the kernel and exposes that state through a file descriptor. Writes add to the counter under defined bounds; reads consume counter state; readiness interfaces expose whether an operation can proceed without blocking. The result is a compact synchronization boundary that fits descriptor-oriented event loops without turning the counter into a byte stream. The interface is Linux-specific. Its guarantees come from the eventfd system-call contract and kernel descriptor semantics, not from the C language or POSIX.

Software Engineering 18 Sep 2026 6 min read

EPOLLEXCLUSIVE Limits Wakeups Across Competing epoll Instances

EPOLLEXCLUSIVE changes which epoll waiters are awakened when several epoll instances monitor the same target. Without the flag, a readiness event can be delivered to every attached epoll instance. With exclusive registration, Linux can wake a smaller subset, reducing redundant scheduling in configurations that otherwise create a thundering herd. The flag changes wakeup distribution. It does not assign permanent ownership of the target descriptor, serialize I/O, or guarantee that exactly one application thread consumes each unit of work.

Linux 18 Sep 2026 4 min read

EPOLLEXCLUSIVE Limits Wakeups Across Competing epoll Instances

A single ready socket can wake several threads when each thread waits on a different epoll instance that watches that socket. Linux provides EPOLLEXCLUSIVE to narrow that wakeup fan-out: among epoll instances that registered the target with the flag, a readiness event wakes one or more rather than all of them. The distinction is deliberately weaker than “exactly one waiter.” EPOLLEXCLUSIVE changes notification selection across epoll instances. It does not transfer ownership of the file descriptor, serialize all I/O, or guarantee that only one thread can observe useful work.

Software Engineering 18 Sep 2026 4 min read

CLOSE_RANGE_UNSHARE Isolates Descriptor Table Cleanup

A thread preparing to cross an execve() boundary can need to remove every file descriptor above a small preserved set while other threads still share its descriptor table. Closing descriptors one by one creates a race: another thread can allocate a descriptor into the interval while cleanup is in progress. Linux close_range() with CLOSE_RANGE_UNSHARE changes the table-sharing boundary before applying the range operation. This behavior matters because a file descriptor number is only an index into a process descriptor table. With CLONE_FILES, multiple tasks can refer to the same table, so a close performed through one task changes descriptor visibility for all tasks sharing it. CLOSE_RANGE_UNSHARE gives the calling task a private descriptor table as part of the operation.

Software Engineering 17 Sep 2026 6 min read

userfaultfd Moves Missing-Page Resolution into User Space

A thread can touch a valid virtual address and stop before the access completes because the page has no present backing yet. With a range registered in UFFDIO_REGISTER_MODE_MISSING, Linux can report that fault through userfaultfd instead of resolving it entirely inside the kernel. A user-space manager then decides which page contents become visible before the blocked access resumes. This changes the ownership of one part of page-fault handling. The kernel still detects the fault, validates the virtual memory area, blocks the faulting execution, and installs mappings through the UFFDIO_* interface. User space gains control over the content and timing of resolution for registered faults.

Linux 17 Sep 2026 5 min read

O_APPEND Couples End Positioning with Each Write

O_APPEND changes a write from two separable actions into one coupled operation: Linux positions the open file description at the current end of the file and performs the write as a single atomic step. That property matters when multiple writers target one regular file. A sequence built from lseek(fd, 0, SEEK_END) followed by write(fd, ...) does not carry the same append semantics because another writer can change the file between those two system calls.

Tech 17 Sep 2026 6 min read

Memory Fences Constrain Cross-Core Memory Ordering

Memory Fences Constrain Cross-Core Memory Ordering A processor can execute memory operations with more freedom than source-code order suggests. Loads may begin early, stores may wait in buffers, cache-coherence traffic may complete at different times, and independent operations can overlap. These techniques improve throughput, but concurrent software needs precise rules for publishing and observing shared state. A memory fence places an ordering constraint around selected memory operations. It does not normally flush every cache, serialize the entire processor, or make all cores execute one instruction stream. Its role is narrower: it restricts which memory-order outcomes are permitted across a defined boundary.

Software Engineering 17 Sep 2026 6 min read

Linux userfaultfd Turns Page Faults Into a Userspace Protocol

A thread can access a valid virtual address and stop before that access completes because another userspace component has been given responsibility for resolving the page fault. With Linux userfaultfd, selected memory ranges can turn faults into descriptor messages while the faulting thread remains blocked until an appropriate resolution operation makes progress possible. This is not a replacement for the kernel’s virtual-memory subsystem. The kernel still detects the fault, validates the registered range, blocks the affected execution path, and performs the page-table operation requested by the manager. The unusual boundary is that userspace can participate in deciding when and with what contents a fault is resolved.

Software Engineering 17 Sep 2026 6 min read

Linux signalfd Moves Signal Delivery Into File-Descriptor Readiness

Linux signalfd Moves Signal Delivery Into File-Descriptor Readiness signalfd() changes the consumption interface for selected Linux signals. Instead of arranging for an asynchronous signal handler to run when one of those signals is delivered, a process can block the signals and receive their information by reading a file descriptor. That descriptor can participate in poll(), epoll, and related readiness mechanisms, so signal handling can share the same dispatch boundary as sockets, pipes, timers, and other pollable objects.

Software Engineering 17 Sep 2026 6 min read

Linux pidfds Turn Process Identity Into a Pollable Handle

A Linux process ID is a number from a reusable namespace. A pidfd is different: it is a file descriptor that refers to a particular process. That distinction changes process management from repeated lookup by numeric name into operations against a kernel-held handle whose identity does not silently retarget when a PID is recycled. The difference is most visible in supervisors, launchers, sandboxes, and service managers that retain process references across asynchronous work. A numeric PID can remain syntactically valid after the original process exits, yet later identify another process. A pidfd keeps the reference tied to the original process object and can also participate in descriptor-oriented event loops.