futex - Linux


Overview

futex is a low-level library call that provides synchronization primitives for multithreaded applications. It allows threads to block and wait for a specific event to occur, or to wake up other threads that are waiting for the same event. Futexes are commonly used for implementing locks, condition variables, and other synchronization primitives in user space.

Syntax

int futex(int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3);

Parameters:

  • uaddr: The address of a shared memory location that contains the value to be operated on.
  • op: The operation to perform. See Options/Flags for available operations.
  • val: The value to compare the shared memory location with (for FUTEX_CMP_REQ).
  • timeout: A pointer to a timespec structure specifying the maximum amount of time to wait (for FUTEX_WAIT).
  • uaddr2: An optional address of a second shared memory location (for FUTEX_WAKE).
  • val3: An optional value to store in the second memory location (for FUTEX_WAKE).

Options/Flags

Operation (op):

  • FUTEX_WAIT: Block until the shared memory location becomes equal to the specified value.
  • FUTEX_WAKE: Wake up the specified number of threads that are waiting on the shared memory location.
  • FUTEX_CMP_REQ: Compare the shared memory location with the specified value and wake up threads if they are equal.
  • FUTEX_WAKE_OP: Wake up all threads that are waiting on the shared memory location and perform the specified operation.

Default Values:

  • timeout: nullptr (wait indefinitely)
  • uaddr2: nullptr
  • val3: 0

Examples

Simple lock implementation using futex:

int lock = 0;

void acquire_lock() {
    while (futex(&lock, FUTEX_WAIT, 0, nullptr, nullptr, 0) != 0)
        ;
}

void release_lock() {
    futex(&lock, FUTEX_WAKE, 1, nullptr, nullptr, 0);
}

Condition variable implementation using futex:

int condition_variable = 0;

void wait_on_condition() {
    while (futex(&condition_variable, FUTEX_WAIT, 0, nullptr, nullptr, 0) != 0)
        ;
}

void signal_condition() {
    futex(&condition_variable, FUTEX_WAKE, 1, nullptr, nullptr, 0);
}

Common Issues

  • Deadlocks: Futexes must be used carefully to avoid deadlocks, where multiple threads are waiting on each other to wake up.
  • Timeouts: Timeouts must be used with caution, as they can cause threads to miss important events if they wake up too early.
  • Incorrect memory addresses: Ensure that the memory addresses passed to futex are valid and accessible to all threads.

Integration

Futexes can be integrated with other system calls and libraries to create more complex synchronization mechanisms. For example:

  • Combined with epoll to implement asynchronous I/O.
  • Used in conjunction with pthreads to implement thread-safe code.

Related Commands

  • pthreads – POSIX threads library for multithreading.
  • epoll – Event-driven I/O library.
  • semaphore – Semaphore-based synchronization primitive.