Documentation
¶
Overview ¶
Package sync provides basic synchronization primitives such as mutual exclusion locks and condition variables.
Values containing the types defined in this package should not be copied.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Cond ¶
type Cond struct {
// contains filtered or unexported fields
}
Cond is a condition variable, a rendezvous point for threads waiting for or announcing the occurrence of an event.
Each Cond is associated with a Mutex, which must be held when changing the condition and when calling Cond.Wait. The zero value is not usable; call Cond.Init before use. A Cond must not be copied after Init.
Example ¶
package main
import (
"solod.dev/so/conc"
"solod.dev/so/sync"
)
type gate struct {
mu sync.Mutex
cond sync.Cond
ready bool
}
func await(arg any) any {
g := arg.(*gate)
g.mu.Lock()
for !g.ready {
g.cond.Wait()
}
println("go!")
g.mu.Unlock()
return nil
}
func main() {
var g gate
g.mu.Init()
g.cond.Init(&g.mu)
defer g.mu.Free()
defer g.cond.Free()
thr := conc.Go(await, &g, nil)
defer thr.Wait()
g.mu.Lock()
g.ready = true
g.cond.Signal()
g.mu.Unlock()
// go!
}
Output:
func (*Cond) Broadcast ¶
func (c *Cond) Broadcast()
Broadcast wakes all threads waiting on c, if any.
func (*Cond) Free ¶
func (c *Cond) Free()
Free releases the resources held by c. The Cond is unusable afterward.
func (*Cond) Init ¶
Init prepares c for use, associating it with mu. It must be called exactly once before any other method. A Cond must not be copied after Init.
func (*Cond) Signal ¶
func (c *Cond) Signal()
Signal wakes at least one thread waiting on c, if any.
func (*Cond) Wait ¶
func (c *Cond) Wait()
Wait atomically unlocks the associated mutex and suspends the calling thread until the Cond is signaled, then re-locks the mutex before returning. The caller must hold the mutex when calling Wait.
func (*Cond) WaitFor ¶
WaitFor behaves like Cond.Wait but stops waiting once nsec nanoseconds have elapsed on the monotonic clock.
Measuring against the monotonic clock keeps the timeout unaffected by wall-clock changes (NTP steps, manual resets). To honor a fixed deadline across spurious wakeups, recompute the remaining time on each call.
WaitFor reports whether it timed out: true means the deadline passed, false means the Cond was signaled. A non-positive nsec times out without blocking.
As with Wait, the caller must hold the mutex and it is re-locked before returning.
type Mutex ¶
type Mutex struct {
// contains filtered or unexported fields
}
Mutex is a mutual exclusion lock.
The zero value is not usable; call Mutex.Init before use. A Mutex must not be copied after Init.
Example ¶
package main
import (
"solod.dev/so/conc"
"solod.dev/so/mem"
"solod.dev/so/sync"
)
type counter struct {
mu *sync.Mutex
val int
}
func increment(arg any) {
c := arg.(*counter)
c.mu.Lock()
c.val++
c.mu.Unlock()
}
func main() {
var mu sync.Mutex
mu.Init()
defer mu.Free()
cnt := counter{mu: &mu, val: 0}
opts := conc.PoolOpts{NumThreads: 4}
pool := conc.NewPool(mem.System, opts)
defer pool.Free()
for range 100 {
pool.Go(increment, &cnt)
}
pool.Wait()
println(cnt.val)
// 100
}
Output:
func (*Mutex) Free ¶
func (m *Mutex) Free()
Free releases the resources held by m. The Mutex is unusable afterward.
func (*Mutex) Init ¶
func (m *Mutex) Init()
Init prepares m for use, leaving it unlocked. It must be called exactly once before any other method. A Mutex must not be copied after Init.
type Once ¶
type Once struct {
// contains filtered or unexported fields
}
Once runs a function exactly once, even when Do is called concurrently from multiple threads.
The zero value is not usable; call Once.Init before use. A Once must not be copied after Init.
Example ¶
package main
import (
"solod.dev/so/conc"
"solod.dev/so/mem"
"solod.dev/so/sync"
)
func hello() {
println("Hello, world!")
}
func onceHello(arg any) {
once := arg.(*sync.Once)
once.Do(hello)
}
func main() {
var once sync.Once
once.Init()
defer once.Free()
opts := conc.PoolOpts{NumThreads: 4}
pool := conc.NewPool(mem.System, opts)
for range 10 {
pool.Go(onceHello, &once)
}
pool.Free()
// Hello, world!
}
Output:
func (*Once) Do ¶
func (o *Once) Do(f func())
Do calls f if and only if Do is being called for the first time for this o. If Do is called concurrently, the callers block until the one call to f returns; every Do returns only after f has completed.
Because no call to Do returns until the one call to f returns, f must not call Do on the same o, or it will deadlock.