Nyx by Example

Mutex

mutex_new() creates a mutual exclusion lock. mutex_lock and mutex_unlock ensure only one thread accesses shared state at a time. Without a mutex, concurrent increments would lose updates due to race conditions.

Code

// Mutex — protecting shared state between threads
// Mutex — proteger estado compartido entre hilos

var counter: int = 0

fn increment_task() -> int {
    let m: int = mutex_new()
    var i: int = 0
    while i < 1000 {
        mutex_lock(m)
        counter = counter + 1
        mutex_unlock(m)
        i = i + 1
    }
    mutex_destroy(m)
    return 0
}

fn main() -> int {
    // Without a mutex, concurrent increments would lose updates.
    // The mutex ensures only one thread modifies counter at a time.
    let h1: int = thread_spawn(increment_task)
    let h2: int = thread_spawn(increment_task)

    thread_join(h1)
    thread_join(h2)

    print("counter: " + int_to_string(counter))
    // Expected: 2000 (1000 per thread, no lost updates)
    return 0
}

Output

counter: 2000

Explanation

mutex_new() allocates a new mutex and returns an opaque handle. Before accessing the shared counter variable, each thread calls mutex_lock(m) to acquire exclusive access, then mutex_unlock(m) to release it.

Two threads each increment the counter 1000 times. Without the mutex, some increments would be lost because both threads could read the same value simultaneously. With the mutex, the final count is always exactly 2000.

Always call mutex_destroy(m) when the mutex is no longer needed to free system resources. In production code, consider wrapping critical sections in helper functions to ensure unlock is never forgotten.

← Previous Next →

Source: examples/by-example/57-mutex.nx