liveBook · Manning

Atomic type

As explained in Modern C, Third Edition

A type specifies the kind of values an entity can represent and the operations applicable to those values.

A shared completion flag

A flag shared between threads can be declared as `_Atomic(bool) finished;`. A plain `bool` is not a safe substitute when one thread may write it while another reads or writes it at the same time. Standard operations on an atomic object are indivisible and linearizable: each appears to take effect as a single operation when reasoning about the threads. section 20.1

An atomic type specifies an object whose standard operations have atomic behavior. The type matters at the declaration: the compiler cannot infer which objects might be accessed concurrently. TAKEAWAY: mark small, critical shared data `_Atomic`; protect code that operates on unprotected shared data with a mutex instead. section 20.1 section 20.8

  // Parameters that will dynamically be changed by
  // different threads
  _Atomic(size_t) constellations; //< Constellations visited
  _Atomic(size_t) x0;             //< Cursor position, row
  _Atomic(size_t) x1;             //< Cursor position, column
  _Atomic(size_t) frames;         //< FPS for display
  _Atomic(bool)   finished;       //< This game is finished.

The declarations mark a completion flag, cursor coordinates, and other values that can change across threads. Each member is atomic; declaring the containing structure does not replace declaring the shared members that need atomic access. section 20.1

Placement changes what has the atomic type. `_Atomic(double[45]) C;` is invalid because atomic cannot be applied to an array; `_Atomic(double) D[45];` declares an array whose elements have atomic type. Atomic qualification also cannot be silently added through a pointer: a pointer to `double` is incompatible with a pointer to atomic `double`. section 20.1

Ordering one atomic object

With `_Atomic(unsigned) x = 11;`, two threads may both update `x`. Its modifications have a modification order consistent with each thread’s sequenced-before order. If one thread reads a value written by the other, that atomic access can synchronize the threads. Atomicity therefore helps with both an individual access and reasoning about which writes a reader observed. section 21.1

Signal handlers impose a narrower test: an operation must appear uninterruptible in that context. The available classes are `sig_atomic_t`, `atomic_flag`, and other atomic types only when they are lock-free. For `sig_atomic_t`, only loads and stores are known to be uninterruptible; `++` is not a sound counter operation there. Atomic types and their type-generic library interfaces arrived with C11; the interfaces cannot generally select an operation by argument size alone. section 19.6 section 18.1.7

How Modern C, Third Edition covers it

How deep it goes
Explains atomic declarations, indivisible operations, modification order, and lock-free limits for signal handlers.
Examples
Shows shared completion and cursor fields, valid and invalid array declarations, a signal-handler counter, and two threads updating one atomic.
What it assumes
Assumes familiarity with C declarations and introduces the concurrency hazard posed by shared non-atomic objects.
What you can do after
Apply it via `_Atomic` to declare small shared objects and distinguish atomic access from mutex-protected critical sections.
How it connects
Connects atomic types to race conditions, mutexes, signal handlers, synchronization, and modification order.

Also explained in

Compare how 17 books explain atomic type →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C, Third Edition. The section links point to the parts of the book it draws on.