///|
async test "broadcast wakes every parked waiter" {
let cond = @cond_var.Cond()
let log = []
@async.with_task_group group => {
for i in 0..<3 {
group.spawn_bg() () => {
cond.wait()
log.push("waiter \{i}: unblocked")
}
}
@async.sleep(50) // ensure all three are parked
log.push("broadcast()")
cond.broadcast()
}
json_inspect(log, content=[
"broadcast()", "waiter 0: unblocked", "waiter 1: unblocked", "waiter 2: unblocked",
])
}///|
async test "signal before wait is lost" {
let cond = @cond_var.Cond()
// Signal first, with no waiters — this signal is dropped.
cond.signal()
// Now park; the signal we issued above will not save us.
@test_util.assert_raise_async () => {
@async.with_timeout(100, () => cond.wait())
}
}///|
async test "signal wakes waiters FIFO" {
let cond = @cond_var.Cond()
let log = []
@async.with_task_group group => {
// Task A parks at ~0 ms.
group.spawn_bg() () => {
cond.wait()
log.push("A")
}
// Task B parks at ~50 ms.
group.spawn_bg() () => {
@async.sleep(50)
cond.wait()
log.push("B")
}
// Two signals, 50 ms apart.
@async.sleep(100)
cond.signal()
@async.sleep(50)
cond.signal()
}
json_inspect(log, content=["A", "B"])
}| You want… | Use |
|---|---|
| Pass values between tasks | @aqueue.Queue |
| Limit how many tasks run something | @semaphore.Semaphore(N) |
| Wake exactly one task on an event | @semaphore.Semaphore(1, initial_value=0) (or Cond.signal with a predicate) |
| Wake every task on an event | @cond_var.Cond with broadcast() |
type CondAsynchronous programming library for MoonBit