Skip to content
FutureBlitz

    Install

    Import std.concurrent.locks

    std.concurrent.locks

    Semaphores, barriers, wait groups, Once, and read-write locks, for any thread.

    The locks any thread can use at once, over the runtime's: a Semaphore of permits, a Barrier that threads meet at, a WaitGroup that waits for work under way, a Once that runs its work one time, and an RwLock<T>, whose value many threads read at once, or one writes alone. Each is a Shared Class, so a Const or a parameter shares one with the work that Spawn and Thread.Start run. What waits blocks its thread and runs nothing else meanwhile, as a Channel's Send and Receive do, so work that waits on the pool holds its worker: work that waits for other work belongs on a Thread, or the pool can be left with no worker for what it waits for. A Semaphore's Acquire and a WaitGroup's Wait can take a Cancellation, which stops the wait.

    std/concurrent/locks.fb

    Types

    Semaphore class

    Public Shared Class Semaphore

    Permits that threads take and give back: Acquire takes one, waiting while there's none, and Release gives them back, so no more threads than there are permits go on at once.

    Examples

    Const permits = Semaphore(2)
    Expect(permits.TryAcquire() && permits.TryAcquire())
    Expect(!permits.TryAcquire())
    permits.Release()
    Expect(permits.Available == 1)

    std/concurrent/locks.fb, line 58

    • @PanicsAtCaller Public New(count: Int) constructor #

      A Semaphore with count permits. Panics when that's negative.

    • Public Method Acquire() method #

      Takes a permit, waiting while there's none.

    • Public Method Acquire(cancel: Cancellation) Throws CancelledError method #

      Takes a permit, waiting while there's none, unless the cancellation is cancelled first, or is already, which throws a CancelledError and takes none.

    • Public Method TryAcquire(): Bool method #

      Takes a permit unless there's none, and tells whether it did.

    • @PanicsAtCaller Public Method Release(count: Int = 1) method #

      Gives back count permits, which needn't be ones Acquire took, waking as many threads waiting for one. Panics when count isn't 1 or more, or when it would take the permits past what an Int holds.

    • Public Property Available: Int property #

      How many permits there are now, which other threads may change at any time.

    Barrier class

    Public Shared Class Barrier

    Where a number of threads meet, round after round: each one's Wait returns once they've all come, which starts the next round.

    Examples

    Global lasts = Atomic<Int>(0)
    Const meet = Barrier(2)
    
    Function Arrive()
        If meet.Wait() Then lasts.Add(1)
    End Function
    
    Local other = Spawn(Arrive)
    Arrive()
    other.Wait()
    // One of the two is the round's last.
    Expect(lasts.Load() == 1)

    std/concurrent/locks.fb, line 124

    • @PanicsAtCaller Public New(count: Int) constructor #

      A Barrier that count threads meet at each round. Panics unless that's 1 or more.

    • Public Method Wait(): Bool method #

      Waits until the round's last thread comes, and then they all go on. Gives True to that last one, and False to the others, so one of them can do what's done once a round.

    • Public Property Count: Int property #

      How many threads meet at it each round.

    WaitGroup class

    Public Shared Class WaitGroup

    A count of the work under way, which Wait waits to see at 0: Add counts work before it starts, and Done says that some is done.

    Examples

    Global finished = Atomic<Int>(0)
    Const work = WaitGroup()
    
    Function Step()
        finished.Add(1)
        work.Done()
    End Function
    
    work.Add(3)
    For i = 1 To 3
        Spawn(Step)
    End For
    
    work.Wait()
    Expect(finished.Load() == 3)

    std/concurrent/locks.fb, line 172

    • Public New() constructor #

      A WaitGroup counting 0.

    • @PanicsAtCaller Public Method Add(count: Int = 1) method #

      Adds count, which can be negative, to the work it counts, and wakes the threads waiting once that's 0. Panics when it would take that below 0, or past what an Int holds.

    • @PanicsAtCaller Public Method Done() method #

      Takes 1 from the count. Panics when it's 0, since Done would be once more than Add counted.

    • Public Method Wait() method #

      Waits until the count is 0, which it may be already.

    • Public Method Wait(cancel: Cancellation) Throws CancelledError method #

      Waits until the count is 0 unless the cancellation is cancelled first, or is already, which throws a CancelledError.

    • Public Property Count: Int property #

      The count now, which other threads may change at any time.

    Once class

    Public Shared Class Once

    Work that runs one time: the first Do runs it, and every other, at once or after, on any thread, returns once it has run.

    Examples

    Global runs = Atomic<Int>(0)
    Const setup = Once()
    
    Function CountRun()
        runs.Add(1)
    End Function
    
    Parallel For i = 0 Until 8
        setup.Do(CountRun)
    End For
    
    Expect(runs.Load() == 1 && setup.IsDone)

    std/concurrent/locks.fb, line 241

    • Public New() constructor #

      A new Once, whose work hasn't run.

    • @PanicsAtCaller Public Method Do(work: Func()) method #

      Runs work, unless a Do has, waiting while another thread's Do runs it. Panics in a Do that the work itself calls, which would wait for itself forever.

    • Public Property IsDone: Bool property #

      Whether the work has run.

    RwLock class

    Public Shared Class RwLock<T: Sendable>

    A value that many threads can read at once, or one can write while no other reads it. A Read gives what its Function makes of the value, and a Write gives the value what its Function makes of it, which no Read sees half done. A writer that waits goes before the readers that come after it, so it isn't kept waiting forever.

    Examples

    Const total = RwLock<Int>(0)
    total.Write(Function(n: Int) => n + 5)
    Expect(total.Read(Function(n: Int) => n * 2) == 10)
    Expect(total.Value == 5)

    std/concurrent/locks.fb, line 286

    • Public New(value: T) constructor #

      A new RwLock that holds value.

    • @PanicsAtCaller Public Method Read<R>(reader: Func(T): R): R method #

      What reader gives for the value, which no thread writes meanwhile, though others may read it. Panics when this thread reads or writes it already, in a reader or a writer, which a writer waiting between could keep waiting forever.

    • @PanicsAtCaller Public Method Write(writer: Func(T): T) method #

      Gives the value what writer gives for it, while no other thread reads or writes it. The old value goes once the Write holds no lock, so a Destroy that its going runs can use the RwLock. Panics when this thread reads or writes it already, which would wait for itself forever.

    • @PanicsAtCaller Public Property Value: T property #

      A copy of the value, as a Read gives it, or a new value, as a Write gives it.

    Report an issue with this page or with FutureBlitz on GitHub.