sync
sync provides synchronous concurrency primitives for threads, locks, channels,
and coordination.
Import
Errors
Fallible synchronization operations return SyncError. Its kind is the typed
sync.SyncErrorKind enum (Invalid, State, Timeout, Closed, Callback,
Spawn, or Io); detail remains textual. Compare or match the enum for
programmatic handling. message() returns the detail for display and
to_string() adds the category. Use SyncError.from_message(text) when
adapting a synchronization failure at an application boundary.
API
sync.spawn(fn() -> T) -> result<Thread<T>, SyncError>; the callback's return value is owned by the worker and delivered once byjoin()sync.sleep(int milliseconds) -> voidThread<T>.join() -> result<T, SyncError>(one-shot)Thread<T>.detach() -> result<void, SyncError>Mutex<T>.with_value(T) -> Mutex<T>Mutex<T>.with_lock(func(&T) returns void) -> result<void, SyncError>RwLock<T>.with_value(T) -> RwLock<T>RwLock<T>.with_read(func(&T) returns void) -> result<void, SyncError>RwLock<T>.with_write(func(&T) returns void) -> result<void, SyncError>CondVar.new() -> CondVarCondVar.wait(mutex: Mutex<T>) -> result<void, SyncError>CondVar.wait_timeout(mutex: Mutex<T>, milliseconds: int) -> result<bool, SyncError>; returnstruewhen notified andfalsewhen the deadline expires. A zero timeout performs a non-blocking check; negative values and values above4_294_967_295milliseconds are rejected so timeout behavior is consistent across Unix and Windows.CondVar.signal() -> result<void, SyncError>CondVar.broadcast() -> result<void, SyncError>AtomicInt.new() -> AtomicInt(initial value0)AtomicInt.with_value(int) -> AtomicIntAtomicInt.load() -> result<int, SyncError>,store(int),add(int),swap(int), andcompare_exchange(int expected, int replacement)AtomicBool.new() -> AtomicBool(initial valuefalse)AtomicBool.with_value(bool) -> AtomicBoolAtomicBool.load() -> result<bool, SyncError>,store(bool),swap(bool), andcompare_exchange(bool expected, bool replacement)Semaphore.with_permits(int) -> result<Semaphore, SyncError>Semaphore.acquire(),try_acquire(),acquire_timeout(milliseconds), andrelease(); timed acquisition returnstrueonly when a permit was acquired before the deadline.Barrier.with_size(int) -> result<Barrier, SyncError>Barrier.wait() -> result<bool, SyncError>; the returned bool identifies the thread that opened the barrierCancellationToken.new() -> CancellationToken,cancel(), andis_cancelled()for cooperative one-way cancellationOnce.new() -> OnceandOnce.call(func() returns void)run a callback at most once; concurrent callers wait for the first invocation to finish.Channel<T>.new() -> Channel<T>(an unbounded default),Channel<T>.new_unbounded() -> Channel<T>, andChannel<T>.new_bounded(int) -> result<Channel<T>, SyncError>create shared MPMC channels; bounded capacity is limited to 16 Mi entries.send(value)blocks, whiletry_send(value)andsend_timeout(value, milliseconds)report whether a bounded send completed; timed channel operations reject values above4_294_967_295milliseconds.recv()blocks and returnssome(value)ornone;try_recv()andrecv_timeout(milliseconds)returnnonewhen no value is ready.close(),is_closed(), andcapacity()provide lifecycle and configuration state.send_cancelled(value, token)andrecv_cancelled(token)stop a blocking operation when the suppliedCancellationTokenis cancelled.Channel<T>.select(channels, timeout_ms)waits for the first available value and returns an optional(index, value)tuple; ties are resolved by input order and closed channels are skipped.WorkerPool<T>.new() -> WorkerPool<T>creates a bounded pool with four workers and a queue capacity of 64.WorkerPool<T>.with_size(int)keeps the default queue policy, whilewith_config(int workers, int queue_capacity)sets both values; both parameterized constructors returnresult<WorkerPool<T>, SyncError>.WorkerPool<T>.map(list<U>, func(U) returns T) -> result<list<T>, SyncError>runs callbacks on the pool and blocks until all submitted work finishes. Results follow input order, even when callbacks finish out of order. An empty input returns an empty list. Closing the pool or cancelling queued tasks during a map returns an error after accepted tasks finish or cancel. Each job gets independent copies of ordinary captured values; synchronization handles keep their shared behavior.WorkerPool<T>.submit(func() returns T) -> result<Channel<T>, SyncError>blocks until work is queued and returns a single-result channel.try_submitandsubmit_timeoutreturnresult<optional<Channel<T>>, SyncError>, usingnonewhen the queue is full or the deadline expires.cancel_pending()reports how many queued callbacks it cancelled, andclose()stops new work and drains accepted work before returning.
with_lock, with_read, and with_write acquire the native lock, pass the
typed payload to a synchronously invoked callback, and release the lock before
returning. The callback receives a borrowed reference and is never retained by
the runtime. A write callback may update the payload; a read callback must only
read it. Mutexes are non-reentrant: acquiring the same mutex again from its
owning thread returns a SyncError instead of blocking or entering recursively.
Mutex<T> and RwLock<T> use the explicit with_value constructors;
they do not overload new() with a payload argument.
Mux panic behavior is process-wide: a panic on a worker thread terminates the
process instead of becoming a recoverable join() error.
Spawned callbacks may capture ordinary owned values, but borrowed references are
rejected because the worker can outlive the referenced scope.
Atomic operations are sequentially consistent. Semaphores and barriers block
the calling thread directly; they do not create futures or background tasks.
Channel payloads are copied values. Resource handles (including sockets,
processes, and other synchronization handles) are rejected as payloads so a
channel cannot smuggle non-thread-safe shared state across workers.
Example
Thread<T> is generic over the callback's return type. A value-producing worker
is joined in exactly the same way:
Condition-variable waits are performed from inside a with_lock callback so
the runtime can atomically release and reacquire the associated mutex while
waiting. wait_timeout uses the same lock discipline and reports whether a
notification arrived before the deadline. Manual lock and unlock methods are
intentionally not part of the Mux surface.
Worker pools own their worker threads and use channels for results. A callback
that has been accepted runs exactly once; closing a pool allows accepted work to
finish, while cancel_pending closes the result channels for callbacks that
never run.