HN
Today

Things Unix can do atomically (2010)

This 2010 post dives deep into the atomic operations available within UNIX-like systems, highlighting how developers can leverage kernel guarantees for thread-safe and multi-process applications without explicit locks. It meticulously catalogs various system calls and their atomic properties, making it a timeless resource for robust system programming. Hacker News finds value in these foundational explanations that empower efficient and reliable software design.

31
Score
2
Comments
#2
Highest Rank
17h
on Front Page
First Seen
Feb 6, 6:00 AM
Last Seen
Feb 6, 10:00 PM
Rank Over Time
22222558101111121414142027

The Lowdown

This post from 2010 catalogs various operations in UNIX-like/POSIX-compliant operating systems that are inherently atomic, offering building blocks for robust, thread-safe, and multi-process-safe programs without resorting to explicit mutexes or read/write locks. The core philosophy is to offload as much work as possible to the kernel, trusting its developers to handle locking more efficiently and reliably than application-level implementations. The author details specific system calls and their atomic characteristics, emphasizing their utility in concurrent programming contexts.

  • Operating on a pathname:
    • mv -T <oldsymlink> <newsymlink> leverages rename(2) to atomically replace a symlink, useful for code deployment.
    • link(oldpath, newpath) creates a hard link, failing with EEXIST if newpath exists, making it a mechanism for whole-file locking visible via ls(1).
    • symlink(oldpath, newpath) creates a symbolic link, providing a similar EEXIST locking mechanism for directories where hard links are not possible.
    • rename(oldpath, newpath) atomically changes a pathname on the same filesystem, failing with ENOENT if oldpath doesn't exist, useful for interprocess locking when files are to be unlinked.
    • open(pathname, O_CREAT | O_EXCL, mode) creates a new file, failing with EEXIST if it already exists, allowing processes to decide who handles a task.
    • mkdir(dirname, mode) creates a new directory, failing with EEXIST if it already exists, providing a locking mechanism for directories similar to open() with O_EXCL.
  • Operating on a file descriptor:
    • fcntl(fd, F_GETLK/F_SETLK/F_SETLKW, &lock) allows cooperative processes to lock regions of a file, with F_SETLKW blocking until the lock is acquired.
    • fcntl(fd, F_GETLEASE/F_SETLEASE, lease) notifies a process via SIGIO when another process accesses or truncates the file, requiring the lease to be removed upon notification.
    • mmap() and msync() enable shared memory access to a file's contents, allowing data sharing between processes with frequent synchronization.
  • Operating on virtual memory:
    • GCC Atomic Builtins (e.g., __sync_fetch_and_add, __sync_val_compare_and_swap) provide full memory barriers, forming the foundation for lock-free algorithms.

By understanding and utilizing these kernel-level atomic operations, developers can build more efficient and reliable concurrent applications, trusting the operating system to handle the complexities of synchronization rather than implementing their own potentially error-prone locking mechanisms.