Documentation ¶
Index ¶
- type Counter
- func (c *Counter) Decrease() (newValue int)
- func (c *Counter) Get() (value int)
- func (c *Counter) Increase() (newValue int)
- func (c *Counter) Set(newValue int) (oldValue int)
- func (c *Counter) Subscribe(subscribers ...func(oldValue, newValue int)) (unsubscribe func())
- func (c *Counter) Update(delta int) (newValue int)
- func (c *Counter) WaitIsAbove(threshold int)
- func (c *Counter) WaitIsBelow(threshold int)
- func (c *Counter) WaitIsZero()
- type DAGMutex
- type KRWMutex
- type LockableEntity
- type MultiMutex
- type Mutex
- type RWMultiMutex
- type RWMutex
- type RWMutexFake
- type Stack
- func (b *Stack[T]) Pop() (element T, success bool)
- func (b *Stack[T]) PopOrWait(waitCondition func() bool) (element T, success bool)
- func (b *Stack[T]) Push(task T)
- func (b *Stack[T]) SignalShutdown()
- func (b *Stack[T]) Size() int
- func (b *Stack[T]) WaitIsEmpty()
- func (b *Stack[T]) WaitSizeIsAbove(threshold int)
- func (b *Stack[T]) WaitSizeIsBelow(threshold int)
- type StarvingMutex
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
}
func NewCounter ¶
func NewCounter() (newCounter *Counter)
func (*Counter) WaitIsAbove ¶
func (*Counter) WaitIsBelow ¶
func (*Counter) WaitIsZero ¶
func (c *Counter) WaitIsZero()
type DAGMutex ¶
type DAGMutex[T comparable] struct { sync.Mutex // contains filtered or unexported fields }
DAGMutex is a multi-entity reader/writer mutual exclusion lock that allows for starvation. Entities can be registered dynamically by providing a comparable identifier. The structure and relation of these entities MUST NOT contain any cycles as this may lead to deadlocks while waiting to acquire locks cyclically.
Entities can be Lock-ed one at a time. The call blocks until the lock for this entity can be acquired. Entities can be RLock-ed multiple in arbitrary order. The call blocks until all read locks can be acquired.
Consider the following example of a DAG with 3 entities A,B,C. ┌───┬─┐ │ │B◄─┐ ┌▼┐ └─┘ │ │A│ │ └▲┘ ┌┴┐ │ │C│ └──────┴─┘
Let's assume the following 3 goroutines are competing for access. Time is advancing with every row. Goroutine 1 Goroutine 2 Goroutine 3
Lock(A) - RLock(A,B) <- blocking, not able to acquire locks work Lock(B) wait Unlock(A) work wait - Unlock(B) wait <- (internally) now RLock(A) is successful, but still waiting for B - - RLock(A, B) <- successful acquired, holding the locks now
func NewDAGMutex ¶
func NewDAGMutex[T comparable]() *DAGMutex[T]
NewDAGMutex creates a new DAGMutex.
func (*DAGMutex[T]) Lock ¶
func (d *DAGMutex[T]) Lock(id T)
Lock locks the given entity for writing. If the lock is already locked for reading or writing, Lock blocks until the lock is available.
func (*DAGMutex[T]) RLock ¶
func (d *DAGMutex[T]) RLock(ids ...T)
RLock locks all given entities for reading. It blocks until all read locks can be acquired.
It should not be used for recursive read locking. A blocked Lock call DOES NOT exclude new readers from acquiring the lock. Hence, it is starving.
func (*DAGMutex[T]) RUnlock ¶
func (d *DAGMutex[T]) RUnlock(ids ...T)
RUnlock unlocks reading for all given entities. It does not affect other simultaneous readers.
func (*DAGMutex[T]) Unlock ¶
func (d *DAGMutex[T]) Unlock(id T)
Unlock unlocks the given entity for writing.
As with Mutexes, a locked DAGMutex is not associated with a particular goroutine. One goroutine may RLock (Lock) an entity within DAGMutex and then arrange for another goroutine to RUnlock (Unlock) it.
type KRWMutex ¶
type KRWMutex struct {
// contains filtered or unexported fields
}
func NewKRWMutex ¶
func NewKRWMutex() *KRWMutex
type LockableEntity ¶
type LockableEntity interface {
// Locks returns the locks that the entity needs to lock.
Locks() (locks []interface{})
}
LockableEntity is an interface that allows to lock (and unlock) entities that are generating complex locks.
type MultiMutex ¶
type MultiMutex struct {
// contains filtered or unexported fields
}
MultiMutex is a mutex that allows to lock multiple entities exclusively. Entities are represented by interface{} identifiers and can be presented in arbitrary order. Goroutine 1 Goroutine 2 Goroutine 3
Lock(a,c) - Lock(c,b) <- blocking work Lock(b) wait
Unlock(a,c) work wait
- Unlock(b) wait
- - Lock(c,b) <- successful
func (*MultiMutex) Lock ¶
func (m *MultiMutex) Lock(ids ...interface{})
Lock blocks until all locks given by ids can be acquired atomically.
func (*MultiMutex) LockEntity ¶
func (m *MultiMutex) LockEntity(entity LockableEntity)
LockEntity locks all locks that are required for the given LockableEntity.
func (*MultiMutex) Unlock ¶
func (m *MultiMutex) Unlock(ids ...interface{})
Unlock releases the locks of ids.
func (*MultiMutex) UnlockEntity ¶
func (m *MultiMutex) UnlockEntity(entity LockableEntity)
UnlockEntity unlocks all locks that are required for the given LockableEntity.
type RWMultiMutex ¶
type RWMultiMutex struct {
// contains filtered or unexported fields
}
func (*RWMultiMutex) Lock ¶
func (mutex *RWMultiMutex) Lock(identifiers ...interface{})
func (*RWMultiMutex) RLock ¶
func (mutex *RWMultiMutex) RLock(identifiers ...interface{})
func (*RWMultiMutex) RUnlock ¶
func (mutex *RWMultiMutex) RUnlock(identifiers ...interface{})
func (*RWMultiMutex) Unlock ¶
func (mutex *RWMultiMutex) Unlock(identifiers ...interface{})
type RWMutexFake ¶
func (*RWMutexFake) RLock ¶
func (m *RWMutexFake) RLock()
func (*RWMutexFake) RUnlock ¶
func (m *RWMutexFake) RUnlock()
type Stack ¶
type Stack[T any] struct { // contains filtered or unexported fields }
func (*Stack[T]) SignalShutdown ¶
func (b *Stack[T]) SignalShutdown()
func (*Stack[T]) WaitIsEmpty ¶
func (b *Stack[T]) WaitIsEmpty()
func (*Stack[T]) WaitSizeIsAbove ¶
func (*Stack[T]) WaitSizeIsBelow ¶
type StarvingMutex ¶
type StarvingMutex struct {
// contains filtered or unexported fields
}
A StarvingMutex is a reader/writer mutual exclusion lock that allows for starvation of readers or writers by first prioritizing any outstanding reader or writer depending on the current mode (continue reading or continue writing). The lock can be held by an arbitrary number of readers or a single writer. The zero value for a StarvingMutex is an unlocked mutex.
A StarvingMutex must not be copied after first use.
If a goroutine holds a StarvingMutex for reading and another goroutine might call Lock, other goroutines can acquire a read lock. This allows recursive read locking. However, this can result in starvation of goroutines that tried to acquire write lock on the mutex. A blocked Lock call does not exclude new readers from acquiring the lock.
func NewStarvingMutex ¶
func NewStarvingMutex() *StarvingMutex
NewStarvingMutex creates a new StarvingMutex.
func (*StarvingMutex) Lock ¶
func (f *StarvingMutex) Lock()
Lock locks starving mutex for writing. If the lock is already locked for reading or writing, Lock blocks until the lock is available.
If there are waiting writers these will be served first before ANY reader can read again. Hence, it is starving.
func (*StarvingMutex) RLock ¶
func (f *StarvingMutex) RLock()
RLock locks starving mutex for reading.
It should not be used for recursive read locking. A blocked Lock call DOES NOT exclude new readers from acquiring the lock. Hence, it is starving.
func (*StarvingMutex) RUnlock ¶
func (f *StarvingMutex) RUnlock()
RUnlock undoes a single RLock call; it does not affect other simultaneous readers. It is a run-time error if mutex is not locked for reading on entry to RUnlock.
func (*StarvingMutex) String ¶
func (f *StarvingMutex) String() (humanReadable string)
String returns a string representation of the StarvingMutex.
func (*StarvingMutex) Unlock ¶
func (f *StarvingMutex) Unlock()
Unlock unlocks starving mutex for writing. It is a run-time error if mutex is not locked for writing on entry to Unlock.
As with Mutexes, a locked StarvingMutex is not associated with a particular goroutine. One goroutine may RLock (Lock) a StarvingMutex and then arrange for another goroutine to RUnlock (Unlock) it.