diff --git a/sync/locker.go b/sync/locker.go index ff691da..57c8d5c 100644 --- a/sync/locker.go +++ b/sync/locker.go @@ -2,7 +2,7 @@ package usync import "sync" -// Locker guards access to a value +// Locker guards access to a value. It must not be copied after first use. type Locker[T any] struct { value T mutex sync.Mutex @@ -34,3 +34,44 @@ func (this *Locker[T]) Borrow () (T, func ()) { this.mutex.Lock() return this.value, this.mutex.Unlock } + +// RWLocker guards separate read/write access to a value. +type RWLocker[T any] struct { + value T + mutex sync.RWMutex +} + +// NewRWLocker creates a new locker with the specified value. It must not be +// copied after first use. +func NewRWLocker[T any] (value T) RWLocker[T] { + return RWLocker[T] { + value: value, + } +} + +// Set sets the value of the locker. +func (this *RWLocker[T]) Set (value T) { + this.mutex.Lock() + defer this.mutex.Unlock() + this.value = value +} + +// Borrow borrows the value from the locker for write access, and returns a +// function that must immediately be deferred, like this: +// +// value, done := locker.Borrow() +// defer done() +// +// From the time Borrow is called to the time the done function is called, it is +// safe to access the locked object from within the current goroutine. +func (this *RWLocker[T]) Borrow () (T, func ()) { + this.mutex.Lock() + return this.value, this.mutex.Unlock +} + +// RBorrow is like Borrow, but returns the item for read access only. Do not +// under any circumstances write to an item returned from this method. +func (this *RWLocker[T]) RBorrow () (T, func ()) { + this.mutex.Lock() + return this.value, this.mutex.Unlock +}