Nyx by Example

Semaphore

A Semaphore from std/sync limits the number of concurrent accesses to a resource. sem_new(n) creates a semaphore with n permits, sem_acquire takes a permit (blocking if none available), and sem_release returns one.

Code

// Semaphore — limiting concurrent access to a resource
// Semáforo — limitar acceso concurrente a un recurso

import "std/sync"

var sem: Semaphore = sem_new(2)
var done: WaitGroup = wg_new()

fn access_resource() -> int {
    sem_acquire(sem)
    print("acquired (count: " + int_to_string(sem_count(sem)) + ")")
    sleep(50)
    sem_release(sem)
    print("released")
    wg_done(done)
    return 0
}

fn main() -> int {
    // Allow at most 2 concurrent accesses
    wg_add(done, 5)

    var i: int = 0
    while i < 5 {
        thread_spawn(access_resource)
        i = i + 1
    }

    wg_wait(done)
    print("all done")
    return 0
}

Output

acquired (count: 1)
acquired (count: 0)
released
released
acquired (count: 1)
acquired (count: 0)
released
released
acquired (count: 1)
released
all done

Explanation

sem_new(2) creates a semaphore with 2 permits. At most 2 threads can hold a permit simultaneously. When a third thread calls sem_acquire, it blocks until one of the first two calls sem_release.

Five threads compete for the semaphore. sem_count returns the number of remaining permits, which drops to 0 when both are taken. After sleeping 50ms (simulating work), each thread releases its permit and signals the WaitGroup.

This pattern is useful for rate-limiting access to external resources like database connections, file descriptors, or API endpoints where you want controlled concurrency rather than full mutual exclusion.

← Previous Next →

Source: examples/by-example/62-semaphore.nx