This allows you to create thread-safe variables which can be loaded, stored, fetched, incremented, decremented, and generally operated on in a thread-safe manner. The primitive type atomics (64-bit and smaller) are implemented by simply disabling interrupts then reenabling them around the "atomic" operation on the given variable, so they are going to be fast and do not require an external mutex or synchronization primitive.
We also support atomic operations on arbitrarily sized buffers and structures. These are going to be locking operations, but they do so using a hash table of spinlocks which are implicitly being mapped to different regions of memory, so you still don't actually have to manually store or handle locking primitives for these.
A great big example that also doubles as a toolchain/KOS back-end test can be found here: https://github.com/KallistiOS/KallistiO ... /atomics.c
Lets note some of the highlights... You can declare atomic variables like so:
Code: Select all
/* Generic buffer structure we will use with atomics. */
typedef struct {
uint8_t values[BUFFER_SIZE];
} Buffer;
/* Atomic data our threads will be competing over accessing. */
static atomic_flag flag_atomic = ATOMIC_FLAG_INIT;
static atomic_bool bool_atomic = false;
static atomic_int int_atomic = INT_MAX;
static _Atomic uint64_t longlong_atomic = 0;
static _Atomic(uint8_t) byte_atomic = 0;
static atomic_short short_atomic = 0;
static atomic_ptrdiff_t ptrdiff_atomic = 0;
static _Atomic(Buffer) buffer_atomic = { {0} };
NOTE: Please note that while the example is for C11, I exhaustively tested the same thing for C++11's std::atomic<> templates and found them all to be working as well. I spent a lot of time with modern C++20 concurency in general, and everything is in working order it seems:
https://twitter.com/falco_girgis/status ... 4117050551
Anyway, happy coedzing, and may your concurrency be lockless!