Module sync/barrier

sync/barrier
Stability: stable — `new`, `wait`, `parties`, `generation` and `waiting` follow the generation model `std::sync::Barrier` and `pthread_barrier_t` both carry, and `wait`'s single `true` is Rust's `BarrierWaitResult::is_leader` without the wrapper struct. `generation` and `waiting` are observability, so they are honest about being a SNAPSHOT: by the time you read either, another party may have arrived. — stable modules only change additively; this one may still change.

Reusable N-party barrier — the generation model, the same one Rust's std::sync::Barrier and POSIX pthread_barrier_t carry.

Every thread that calls wait() blocks until parties threads have called it. All of them are then released together, the barrier resets, and it can be used again for the next round. Exactly one of the released threads — the last to arrive, which is the one that tripped the barrier — gets true back from wait(), so a caller can nominate a single thread to do the between-rounds bookkeeping (Rust spells this BarrierWaitResult::is_leader).

{ Barrier } :: import "std/sync/barrier";
{ Thread } :: import "std/thread";

b := Barrier.new(i32(3));
t1 := Thread(unit).spawn((io) => { b.wait(); });
t2 := Thread(unit).spawn((io) => { b.wait(); });
b.wait();  // the third party — all three proceed from here
t1.join();
t2.join();

Stability

stable — new, wait, parties, generation and waiting follow the generation model std::sync::Barrier and pthread_barrier_t both carry, and wait's single true is Rust's BarrierWaitResult::is_leader without the wrapper struct. generation and waiting are observability, so they are honest about being a SNAPSHOT: by the time you read either, another party may have arrived.

Types

Barrier atomic object
Barrier

Reusable barrier built on Mutex and Cond. Uses atomic reference counting for safe cross-thread sharing.

_generation is what makes the barrier reusable and correct. A waiter samples it on arrival and sleeps until it CHANGES, rather than sleeping until _count returns to zero: a thread from the round that just tripped can re-enter the barrier and bump _count before a slower sibling of the previous round has been scheduled, so _count alone cannot tell that sibling whether its own round is over. The generation can, because it only ever moves forward.

Fields

NameTypeDescription
_partiesi32
_counti32
_generationi64
_mutexMutex(bool)
_cvCond
impl(Barrier, ...)
new : (Barrier) fn(parties : i32) -> Barrier

Create a barrier that trips once parties threads are waiting on it.

parties <= 1 yields a barrier that never blocks: the single arriving thread trips it immediately and is its own leader.

Parameters

NameTypeNotesDescription
partiesi32

The number of threads this barrier trips on. Fixed at construction.

Returns: Barrier

wait : (Barrier) fn(self : Barrier) -> bool

Block until parties threads have called wait(). Returns true in exactly one of them per generation — the thread that tripped the barrier.

Parameters

NameTypeNotes
selfBarrier

Returns: bool

parties : (Barrier) fn(self : Barrier) -> i32

The number of threads this barrier trips on. Fixed at construction.

Parameters

NameTypeNotes
selfBarrier

Returns: i32

generation : (Barrier) fn(self : Barrier) -> i64

How many times the barrier has tripped so far — the round a caller arriving now would join.

Parameters

NameTypeNotes
selfBarrier

Returns: i64

waiting : (Barrier) fn(self : Barrier) -> i32

How many threads are currently parked in wait() for the round in progress. Informational only.

Parameters

NameTypeNotes
selfBarrier

Returns: i32