Documentation ¶
Overview ¶
Package latch provides a notification-based counter latch.
Index ¶
- type Counter
- func (l *Counter) Apply(delta int)
- func (l *Counter) Count() int64
- func (l *Counter) Hold()
- func (l *Counter) Lock()
- func (l *Counter) Release()
- func (l *Counter) Unlock()
- func (l *Counter) Wait() <-chan WaitStatus
- func (l *Counter) WaitHold(holds int) <-chan WaitStatus
- func (l *Counter) WaitLock() <-chan WaitStatus
- type Option
- type WaitStatus
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Counter ¶
type Counter struct {
// contains filtered or unexported fields
}
Counter is conceptually similar to a sync.WaitGroup, except that it does not require foreknowledge of how many tasks there will be, and it uses a notification-style API. That it, it can count both up and down.
It is always valid to add or remove holds on the Counter, regardless of their ordering with Wait. For example, a Counter can be used to track the completion of tasks that spawn an unknown number of sub-tasks.
The Wait methods on a Counter will trigger when the count is exactly zero.
Counter additionally implements sync.Locker. When the latch is in a locked state, no changes to the Counter's count may be made.
A Counter should not be copied.
Example (Hierarchy) ¶
This example shows how a Counter can be used in a manner similar to a sync.WaitGroup, but where the total number of sub-processes is unknown to the parent process.
// The "work" will be to increment this value; it's not relevant to // the use of the latch. var dummyWork int32 // Latches must be constructed, the zero value isn't useful. latch := New() // Spawn a number of child goroutines. for i := 0; i < 10; i++ { latch.Hold() go func() { defer latch.Release() // Do work. atomic.AddInt32(&dummyWork, 1) // Spawn grand-children goroutines. for j := 0; j < 10; j++ { latch.Hold() go func() { defer latch.Release() // Do more work. atomic.AddInt32(&dummyWork, 1) }() } }() } // The top level code can wait for the unknown number of child // routines to finish. Since the API is channel-based, it can be // combined with select statements for conditional flow control. select { case <-latch.Wait(): fmt.Printf("%d processes ran, with %d holds pending", atomic.LoadInt32(&dummyWork), latch.Count()) case <-time.After(time.Second): fmt.Println("Timed out") }
Output: 110 processes ran, with 0 holds pending
func (*Counter) Apply ¶
Apply changes the hold-count on the latch.
This method will panic if a negative delta exceeds the number of holds on the Counter.
func (*Counter) Count ¶
Count returns an estimate of the number of pending holds.
This method is not subject to locking and is safe to call at any time. This makes it suitable as a source for metrics collection.
func (*Counter) Hold ¶
func (l *Counter) Hold()
Hold increments the use-count by 1.
It is a shortcut for Apply(1).
func (*Counter) Lock ¶
func (l *Counter) Lock()
Lock will lock the underlying sync.Locker used by the Counter.
This has the effect of blocking all other uses of the Counter until a call to Unlock is made.
func (*Counter) Release ¶
func (l *Counter) Release()
Release decrements the use-count by 1.
It is a shortcut for Apply(-1).
func (*Counter) Unlock ¶
func (l *Counter) Unlock()
Unlock will unlock the underlying sync.Locker used by the Counter.
func (*Counter) Wait ¶
func (l *Counter) Wait() <-chan WaitStatus
Wait returns a channel that will emit a single value once the wait condition has been (instantaneously) satisfied.
Consider using WaitLock if it is necessary to prevent additional holds from being obtained until a call to Unlock is made.
func (*Counter) WaitHold ¶
func (l *Counter) WaitHold(holds int) <-chan WaitStatus
WaitHold returns a channel that will emit a single value once the wait condition has been (instantaneously) satisfied and the requested number of holds has been added.
This method will panic if holds is negative.
func (*Counter) WaitLock ¶
func (l *Counter) WaitLock() <-chan WaitStatus
WaitLock returns a channel that will emit a single value once the wait condition has been (instantaneously) satisfied and the Counter has been left in a locked state.
Callers to this method must ensure that Unlock is called after receiving the notification.
type Option ¶
type Option struct {
// contains filtered or unexported fields
}
Option allows the behavior of a Counter to be tuned.
func WithLocker ¶
WithLocker constructs a Counter that is externally synchronized using the given sync.Locker.
type WaitStatus ¶
type WaitStatus int
WaitStatus is returned from the Wait functions.
func (WaitStatus) Delayed ¶
func (s WaitStatus) Delayed() bool
Delayed returns true if the call to Wait was delayed by existing holds.
func (WaitStatus) Locked ¶
func (s WaitStatus) Locked() bool
Locked returns true if the call to wait left the Counter in a locked state.