Un Semaphore de std/sync limita el número de accesos concurrentes a un recurso. sem_new(n) crea un semáforo con n permisos, sem_acquire toma un permiso (bloqueando si no hay ninguno disponible), y sem_release devuelve uno.
// Semaphore — limiting concurrent access to a resource // Semáforo — limitar acceso concurrente a un recurso import "std/sync" // Stateful handles (Semaphore/WaitGroup/mutex_new()) are SAFE as global // initializers — they run single-threaded before main (since v0.24.27). // Never lazy-init them behind a READY flag: that's a data race (see LLM.md). // ES: los handles con estado son SEGUROS como inicializadores globales — // corren single-threaded antes de main. Nunca lazy-init detrás de un flag. 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 }
acquired (count: 1) acquired (count: 0) released released acquired (count: 1) acquired (count: 0) released released acquired (count: 1) released all done
Cómo funciona
sem_new(2) crea un semáforo con 2 permisos. Como máximo 2 hilos pueden tener un permiso al mismo tiempo. Cuando un tercer hilo llama a sem_acquire, se bloquea hasta que uno de los dos primeros llame a sem_release.
Cinco hilos compiten por el semáforo. sem_count devuelve el número de permisos restantes, que cae a 0 cuando ambos están tomados. Después de dormir 50 milisegundos (simulando trabajo), cada hilo libera su permiso y avisa al WaitGroup.
Este patrón es útil para limitar la velocidad de acceso a recursos externos como conexiones de base de datos, descriptores de archivo o endpoints de API, donde se desea concurrencia controlada en lugar de exclusión mutua total.