C Atomic Operations (<stdatomic.h>)
Thread-safe operations without locks
⚛️ What is stdatomic.h?
The stdatomic.h header provides atomic operations for lock-free programming. Atomic operations are indivisible and thread-safe, allowing concurrent access to shared variables without explicit synchronization mechanisms like mutexes.
#include <stdatomic.h>
#include <stdio.h>
atomic_int counter = 0;
atomic_fetch_add(&counter, 1);
Key Atomic Concepts
Atomic Types
Thread-safe variable types
atomic_int count;
atomic_bool flag;
atomic_long value;
Atomic Load
Safely read atomic variables
int val = atomic_load(&counter);
printf("Value: %d\n", val);
Atomic Store
Safely write to atomic variables
atomic_store(&counter, 42);
// Thread-safe assignment
Atomic Operations
Perform atomic arithmetic
atomic_fetch_add(&counter, 5);
atomic_fetch_sub(&counter, 2);
🔹 Basic Atomic Counter
Atomic operations ensure thread-safe counter updates in multithreaded applications without explicit locking mechanisms or synchronization primitives. Use atomic_int and operations like atomic_fetch_add() for lock-free concurrent access. Atomic operations from stdatomic.h provide guarantees that operations complete without interruption. Multiple threads can safely increment counters simultaneously without data races or corruption. Atomic operations are fundamental for high-performance concurrent programming where performance and correctness must coexist.
#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>
atomic_int global_counter = 0;
int worker_thread(void* arg) {
for (int i = 0; i < 1000; i++) {
// Atomic increment - no mutex needed!
atomic_fetch_add(&global_counter, 1);
}
return 0;
}
int main() {
thrd_t threads[3];
// Create 3 threads
for (int i = 0; i < 3; i++) {
thrd_create(&threads[i], worker_thread, NULL);
}
// Wait for all threads
for (int i = 0; i < 3; i++) {
thrd_join(threads[i], NULL);
}
printf("Final counter: %d\n", atomic_load(&global_counter));
return 0;
}
Output:
Final counter: 3000
🔹 Compare and Swap
Atomic compare-and-swap operations are essential for building lock-free algorithms in concurrent programming. The atomic_compare_exchange function checks if a variable holds an expected value and atomically replaces it with a new value if the comparison succeeds. This operation is fundamental for thread-safe data structures because it prevents race conditions without using expensive locks. For example, atomic_compare_exchange_strong(&value, &expected, 20) will change the value to 20 only if it currently equals the expected value, returning true on success. This technique enables high-performance concurrent algorithms that scale efficiently across multiple processor cores.
#include <stdatomic.h>
#include <stdio.h>
atomic_int shared_value = 10;
int main() {
int expected = 10;
int desired = 20;
// Try to change value from 10 to 20
if (atomic_compare_exchange_strong(&shared_value, &expected, desired)) {
printf("Successfully changed %d to %d\n", expected, desired);
} else {
printf("Failed to change, current value: %d\n", expected);
}
printf("Current value: %d\n", atomic_load(&shared_value));
return 0;
}
Output:
Successfully changed 10 to 20
Current value: 20