Skip to content

Synchronization methods

Finalspace edited this page May 29, 2026 · 2 revisions

Table of Contents

Why synchronization is needed

When multiple Threads access the same data, reads and writes can interleave in any order.

Without synchronization the result is a race condition: lost updates, torn reads, or inconsistent state.

Even a single statement like counter++ is not atomic - it is a load, an add and a store.

Two threads running it in parallel can both read the same value, add one, and write back the same result - losing one increment.

Synchronization primitives serialize access to shared data or signal state changes between Threads, so the program behaves as intended.

Solving race conditions

Mutex - protect a critical section

Use a fplMutexHandle to ensure only one Thread executes a code section at a time.

static  counterMutex;
static uint32_t sharedCounter;

void IncrementCounter() {
    (&counterMutex);
    ++sharedCounter; // safe: only one Thread at a time
    (&counterMutex);
}

Signal - notify waiting Threads

Use a fplSignalHandle when one Thread must tell others that something happened (e.g. work is ready).

static  workReady;

void ProducerThread() {
    // ... produce work ...
    (&workReady); // wake all waiters
}

void ConsumerThread() {
    (&workReady, );
    // ... consume work ...
}

Condition-Variable - wait for a predicate

Use a fplConditionVariable together with a fplMutexHandle when waiters must check a condition under a lock and re-check after wakeup.

static  queueMutex;
static  queueCond;
static int itemCount;

void Push() {
    (&queueMutex);
    ++itemCount;
    (&queueCond); // wake one waiter
    (&queueMutex);
}

void Pop() {
    (&queueMutex);
    while (itemCount == 0) { // re-check after wakeup
        (&queueCond, &queueMutex, );
    }
    --itemCount;
    (&queueMutex);
}

Semaphore - limit concurrent access

Use a fplSemaphoreHandle to allow up to N Threads into a section at the same time.

static  pool; // init with N permits

void UseResource() {
    (&pool, ); // take a permit
    // ... use one of N shared resources ...
    (&pool); // give it back
}

Atomics - lock-free single-value updates

Use atomics when only a single integer or pointer needs to be updated safely, without a Mutex.

static volatile uint32_t counter;

void IncrementCounter() {
    (&counter, 1); // safe without a lock
}

Comparison

Primitive Purpose Scope Cost Notes
fplMutexHandle Mutual exclusion of a code section Same process Low Only the owner Thread can unlock
fplSignalHandle Notify one or many waiters Cross-process Medium Set/Reset is not Thread-Safe by itself
fplConditionVariable Wait for a predicate under a Mutex Same process Medium Requires a Mutex; supports signal and broadcast
fplSemaphoreHandle Limit N concurrent accessors Same process Medium Any Thread can release; counted permits
Atomics Lock-free op on a single value Same process Lowest One variable at a time; includes a memory barrier

Note: Pick the lightest primitive that fits the problem. Atomics for a single value, a Mutex for a small critical section, a Condition-Variable when waiting on a predicate, a Semaphore for bounded resources, a Signal for cross-process or fan-out notifications.

Final Platform Layer

Pages

Topics

Data Structures

Clone this wiki locally