Under heavy development. This site describes the intended 1.0 language. Current features and performance vary. Development status
Sn50SnThe SnAPI programming language
Development · Evolving reference

Semaphore

Owns bounded native semaphore permits independently from the task runtime. Separate published readonly borrows may wait/release/close concurrently. Moving the owner itself requires external synchronization. Wait blocks its thread; TryWait does not wait for a permit. Release publishes protected effects before successful acquisition. Close rejects new commits and wakes blocked waits; no FIFO/starvation guarantee or automatic permit release is made.

Sn is under heavy development. This reference includes the intended 1.0 design; features may be incomplete in the current compiler. Read the status →

Module std.sync

import std.sync;

Public declaration contracts and authored examples. A page can document several related symbols. Implementation bodies are excluded.

Semaphore

pub final class Semaphore

Owns bounded native semaphore permits independently from the task runtime. Separate published readonly borrows may wait/release/close concurrently. Moving the owner itself requires external synchronization. Wait blocks its thread; TryWait does not wait for a permit. Release publishes protected effects before successful acquisition. Close rejects new commits and wakes blocked waits; no FIFO/starvation guarantee or automatic permit release is made.

Example

module example.semaphore;
from std.sync import Semaphore;
fn Main() -> i32 {
    var Gate = {
        // Keep writable result storage through the explicit noncopy payload transfer.
        var GateCreation = Semaphore.TryCreate(1, 2);
        switch GateCreation {
            case .Ok { Value = Value: mut Semaphore& } => break move(Value);
            case .Err => return 1;
        }
    };
    if Gate.Wait() is .Err { Error = _ } { return 2; }
    switch Gate.TryWait() { case .Ok { Value = Acquired } => { if Acquired { return 3; } } case .Err => return 4; }
    if Gate.Release(2) is .Err { Error = _ } { return 5; }
    if (Gate.Release() is .Ok) { return 6; }
    if Gate.Wait() is .Err { Error = _ } { return 7; }
    var Moved = move(Gate);
    if !Gate.IsEmpty { return 8; }
    Moved.Close(); Moved.Close();
    if Moved.TryWait() is .Ok { Value = _ } { return 9; }
    return 0;
}

Semaphore.init

pub init()

Starts inert without allocation or native resources.

Semaphore.init

pub init(Source: readonly Self&) = delete;

Rejects copying native authority. Source: Existing owner.

Semaphore.init

pub init(Source: mut Self&&)

Moves native authority and leaves Source inert. Source: Transferred owner.

Semaphore.operator

pub fn operator =(Source: readonly Self&) -> void = delete;

Rejects copying native authority. Source: Existing owner. Return: No runtime result; this assignment is deleted and cannot be invoked.

Semaphore.operator

pub fn operator =(Source: mut Self&&)

Closes/releases old authority before moving Source; self-move is unchanged. Source: Transferred owner left inert. Return: No value after closing and releasing displaced authority, then transferring Source; exact self-move is unchanged.

Semaphore.IsEmpty

pub IsEmpty: bool;

Reports default/moved ownership; a closed owned semaphore is not empty.

Semaphore.TryCreate

pub static fn TryCreate(InitialCount: u64, MaximumCount: u64) -> Result<Self, SemaphoreError>

Creates checked native permit storage, possibly allocating. InitialCount: Initially available permits. MaximumCount: Positive capacity. Return: Owned semaphore or count/allocation/provider error.

Semaphore.TryCreate

pub static fn TryCreate() -> Result<Self, SemaphoreError>

Supplies the omitted arguments to TryCreate. Note: Defaults: InitialCount = 0, MaximumCount = 18446744073709551615_u64. Return: The full synchronous operation's owned success value or typed failure.

Semaphore.TryCreate

pub static fn TryCreate(InitialCount: u64) -> Result<Self, SemaphoreError>

Supplies the omitted arguments to TryCreate. Note: Defaults: MaximumCount = 18446744073709551615_u64. InitialCount: Same input, ownership and lifetime contract as the full operation. Return: The full synchronous operation's owned success value or typed failure.

Semaphore.Wait

pub readonly fn Wait() -> Result<void, SemaphoreError>

Blocks this thread until one permit commits, close wins or provider fails. Return: Success after consuming one permit, otherwise portable error.

Semaphore.WaitAsync

pub readonly async fn WaitAsync(Token: CancellationToken) -> Task<Result<void, SemaphoreError>>

Waits for one permit without occupying a worker while pending. Token: Owned retained cancellation observation, inert by default. Return: Success after acquisition, or portable cancellation/closure/provider error. Receiver backing must survive this task under ordinary async borrowing rules. Release/close callbacks only queue continuations. Cancellation cannot revoke a committed acquisition and acquired permits are not automatically returned.

Example

module example.semaphore_async;
from std.sync import Semaphore;
from std.task import Task, CancellationSource;
async fn Main() -> Task<i32> {
    let Gate = {
        // Keep writable result storage through the explicit noncopy payload transfer.
        var GateCreation = Semaphore.TryCreate(1, 1);
        switch GateCreation {
            case .Ok { Value = Value: mut Semaphore& } => break move(Value);
            case .Err => return 1;
        }
    };
    switch await Gate.WaitAsync() { case .Ok => {} case .Err => return 2; }
    let Source = {
        // Keep writable result storage through the explicit noncopy payload transfer.
        var SourceCreation = CancellationSource.TryCreate();
        switch SourceCreation {
            case .Ok { Value = Value: mut CancellationSource& } => break move(Value);
            case .Err => return 3;
        }
    };
    Source.RequestCancellation();
    switch await Gate.WaitAsync(Source.Token) {
        case .Ok => return 4;
        case .Err { Error = Error } => { if !(Error is .Cancelled) { return 5; } }
    }
    if Gate.Release() is .Err { Error = _ } { return 6; }
    Gate.Close();
    switch await Gate.WaitAsync() {
        case .Ok => return 7;
        case .Err { Error = Error } => { if !(Error is .Closed) { return 8; } }
    }
    return 0;
}

Semaphore.WaitAsync

pub readonly fn WaitAsync() -> Task<Result<void, SemaphoreError>>

Supplies the omitted arguments to WaitAsync. Note: Defaults: Token = CancellationToken(). Return: Exact full-operation result; no additional async frame is created.

Semaphore.TryWait

pub readonly fn TryWait() -> Result<bool, SemaphoreError>

Attempts one permit without waiting for availability. Return: True if consumed, false if busy, otherwise portable error.

Semaphore.Release

pub readonly fn Release(Count: u64) -> Result<void, SemaphoreError>

Atomically adds all requested permits or changes nothing on error. Count: Permits added; zero is an open-state no-op. Return: Success or limit/close/provider error.

Semaphore.Release

pub readonly fn Release() -> Result<void, SemaphoreError>

Supplies the omitted arguments to Release. Note: Defaults: Count = 1. Return: The full synchronous operation's success or typed failure.

Semaphore.Close

pub readonly fn Close() -> void

Idempotently rejects new commits and wakes waiters; inert owners are unchanged. Return: No value; does not join or revoke acquired permits.

Documentation snapshot: October 24, 2026 About versions ↗
Searching Development · language & standard library