Documentation
¶
Overview ¶
Package msync defines some helpful types for managing concurrency.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Link ¶ added in v0.7.0
type Link[T any] struct { // contains filtered or unexported fields }
Link is a snapshot of a Value acquired by a call to its LoadLink method. Use Link.Get to obtain the captured value. The captured value is fixed, and does not change if the underlying Value is updated separately.
A linked snapshot is either "valid" or "invalid". It is "valid" if a call to Link.StoreCond or Link.UpdateCond could succeed at some point in the future; otherwise it is "invalid". A valid snapshot may become invalid, but an invalid snapshot is permanently so. See also: Link.Validate.
Example ¶
package main
import (
"fmt"
"log"
"github.com/creachadair/msync"
)
func main() {
s := msync.NewValue(1)
// Links support a form of optimistic transaction control, allowing the
// caller do detect whether its view of state has changed due to the actions
// of other goroutines.
//
// Call LoadLink to obtain a view. The view is a snapshot of the value at
// the moment the link was taken.
v := s.LoadLink(nil)
fmt.Printf("snapshot: %d\n", v.Get())
// After doing some work, we would like to update s to some new value, but
// only if s has not been separately modified (which means our view is no
// longer current). Call StoreCond to update the value if the view is still
// current:
if v.StoreCond(2) {
fmt.Printf("update succeeded, now %d\n", v.Get())
}
// A successful update acts as a "commit", and the link becomes invalid.
if v.Validate() {
log.Fatal("unexpected")
}
// We can re-link to get a new snapshot. It is OK to reuse a link once it is
// known to be invalid (e.g., after a call to StoreCond).
s.LoadLink(v)
// Time passes. While we are working, another goroutine modifies the value.
// This call is not in a separate goroutine, but simulates the effect.
s.Set(4)
// After completing our work, we want to update, but now our snapshot is no
// longer current, so the update will fail. We can retry or report an error.
if v.StoreCond(3) {
log.Fatal("unexpected")
}
// A failed update invalidates the link.
if v.Validate() {
log.Fatal("unexpected")
}
// The underlying value has the last successful update.
fmt.Printf("view now: %d\n", v.Get())
fmt.Printf("value now: %d\n", s.Get())
// We can also use a Link to check whether our view is still current without
// updating the value:
s.LoadLink(v)
// ... time passes ...
// Validate reports whether StoreCond would have succeeded, but does not
// actually modify the underlying value. If Validate reports true, the view
// is still current as of this moment.
fmt.Printf("view %d still current: %v\n", v.Get(), v.Validate())
}
Output: snapshot: 1 update succeeded, now 2 view now: 2 value now: 4 view 4 still current: true
func (*Link[T]) Get ¶ added in v0.7.0
func (lv *Link[T]) Get() T
Get returns the value captured in the snapshot.
func (*Link[T]) StoreCond ¶ added in v0.7.0
StoreCond attempts to update the linked Value with v, and reports whether the update succeeded. An update succeeds if no successful StoreCond, UpdateCond, Set, or Update operation has been applied to the linked Value since the Value.LoadLink that initialized lv.
Once StoreCond has been called, whether successful or not, lv is invalid. It is safe to re-link and reuse an invalid Link. If StoreCond succeeds, the Get method returns the updated value.
func (*Link[T]) UpdateCond ¶ added in v0.9.1
UpdateCond attempts to update the linked Value with f, and reports whether the update succeeded. An update succeeds if no successful StoreCond, UpdateCond, Set, or Update operation has been applied to the linked Value since the Value.LoadLink that initialized lv. If an update is not possible, f is not called.
Once UpdateCond has been called, whether successful or not, lv is invalid. It is safe to re-link and reuse an invalid Link. If UpdateCond succeeds, the Get method returns the updated value.
The pointer passed to f will never be nil.
func (*Link[T]) Validate ¶ added in v0.7.0
Validate reports whether a call to Link.StoreCond or Link.UpdateCond would have succeeded given the current state of lv. When Validate reports true, it means lv was valid at the time of the call; it may have become invalid by the time the caller receives the result. If Validate reports false, lv is invalid. It is safe to re-link and reuse an invalid Link.
type Value ¶ added in v0.0.2
type Value[T any] struct { // contains filtered or unexported fields }
A Value is a mutable container for a single value of type T that can be concurrently accessed by multiple goroutines. A zero Value is ready for use, but must not be copied after its first use.
The Value takes ownership of the value in its custody. In particular, if a pointer or a slice is stored in a Value, the caller must not modify the contents without separate synchronization.
Example ¶
package main
import (
"fmt"
"log"
"sync"
"time"
"github.com/creachadair/msync"
)
func main() {
var s msync.Value[string]
var wg sync.WaitGroup
defer wg.Wait()
// Callers can use Set to modify the value concurrently.
wg.Go(func() { s.Set("apple") })
wg.Go(func() { s.Set("pear") })
wg.Go(func() { s.Set("plum") })
wg.Go(func() { s.Set("cherry") })
// Use Wait to block until a new value becomes available.
select {
case <-time.After(10 * time.Second):
log.Fatal("Timeout waiting for value to change")
case <-s.Wait():
fmt.Printf("Value updated, now %v\n", s.Get())
}
// Use Get to fetch the current value at any time.
fmt.Println(s.Get())
}
Output:
func (*Value[T]) Get ¶ added in v0.0.2
func (v *Value[T]) Get() T
Get returns the current value stored in v.
func (*Value[T]) LoadLink ¶ added in v0.2.0
LoadLink links a view of the current value of v. If lv == nil, a new link is allocated and returned. Otherwise, the contents of *lv are replaced and lv is returned.
func (*Value[T]) Set ¶ added in v0.0.2
func (v *Value[T]) Set(newValue T)
Set updates the value stored in v to newValue. Calling Set also wakes any goroutines that are blocked on a Wait channel. Set invalidates any linked snapshots open on v, even if the target value does not change.
func (*Value[T]) Update ¶ added in v0.9.1
func (v *Value[T]) Update(f func(*T))
Update updates the value stored in v in-place using f. Calling Update also wakes any goroutines that are blocked on a Wait channel, and invalidates any linked snapshots open on v.
The pointer passed to f will never be nil.
func (*Value[T]) Wait ¶ added in v0.0.2
func (v *Value[T]) Wait() <-chan struct{}
Wait returns a channel that is closed the next time the value of v is set via Value.Set or a successful call to Link.StoreCond.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package throttle allows calls to a function to be coalesced among multiple concurrent goroutines.
|
Package throttle allows calls to a function to be coalesced among multiple concurrent goroutines. |
|
Package trigger implements a channel-based condition variable.
|
Package trigger implements a channel-based condition variable. |