semaphore

package
v2.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 8, 2023 License: Apache-2.0 Imports: 7 Imported by: 6

Documentation

Overview

Package semaphore provides a simple channel-based semaphore that optionally honors context semantics.

Index

Examples

Constants

View Source
const (
	MetricOpen   float64 = 1.0
	MetricClosed float64 = 0.0
)

Variables

View Source
var (
	// ErrClosed is returned when a closeable semaphore has been closed
	ErrClosed = errors.New("the semaphore has been closed")
)
View Source
var (
	// ErrTimeout is returned when a timeout occurs while waiting to acquire a semaphore resource.
	// This error does not apply when using a context.  ctx.Err() is returned in that case.
	ErrTimeout = errors.New("The semaphore could not be acquired within the timeout")
)

Functions

This section is empty.

Types

type Closeable

type Closeable interface {
	io.Closer
	Interface

	// Closed() returns a channel that is closed when this semaphore has been closed.
	// This channel has similar use cases to context.Done().
	Closed() <-chan struct{}
}

Closeable represents a semaphore than can be closed. Once closed, a semaphore cannot be reopened.

Any goroutines waiting for resources when a Closeable is closed will receive ErrClosed from the blocked acquire method. Subsequent attempts to acquire resources will also result in ErrClosed.

Both Close() and Release() are idempotent. Once closed, both methods return ErrClosed without modifying the instance.

func CloseableMutex

func CloseableMutex() Closeable

CloseableMutex is syntactic sugar for NewCloseable(1)

func InstrumentCloseable

func InstrumentCloseable(c Closeable, o ...InstrumentOption) Closeable

InstrumentCloseable is similar to Instrument, but works with Closeable semaphores. The WithClosed option is honored by this factory function.

func NewCloseable

func NewCloseable(count int) Closeable

NewCloseable returns a semaphore which honors close-once semantics.

A Closeable semaphore has a very narrow set of use cases. Closing the semaphore signals any goroutines waiting for resources that those resources are no longer available. This is useful in situations where a transient resource, such as an external connection, will be shut down. In order to implement closeable-ness, a Closeable sacrifices some performance in the Acquire* methods. For more general semaphore use cases, use New() or Mutex() instead.

type InstrumentOption

type InstrumentOption func(*instrumentOptions)

InstrumentOption represents a configurable option for instrumenting a semaphore

func WithClosed

func WithClosed(s xmetrics.Setter) InstrumentOption

WithClosed sets a gauge that records the state of a Closeable semaphore, 1.0 for open and 0.0 for closed. This option is ignored for regular semaphores.

func WithFailures

func WithFailures(a xmetrics.Adder) InstrumentOption

WithFailures establishes a metric that tracks how many times a resource was unable to be acquired, due to timeouts, context cancellations, etc.

func WithResources

func WithResources(a xmetrics.Adder) InstrumentOption

WithResources establishes a metric that tracks the resource count of the semaphore. If a nil counter is supplied, resource counts are discarded.

type Interface

type Interface interface {
	// Acquire acquires a resource.  Typically, this method will block forever.  Some semaphore implementations,
	// e.g. closeable semaphores, can immediately return an error from this method.
	Acquire() error

	// AcquireWait attempts to acquire a resource before the given time channel becomes signaled.
	// If the resource was acquired, this method returns nil.  If the time channel gets signaled
	// before a resource is available, ErrTimeout is returned.
	AcquireWait(<-chan time.Time) error

	// AcquireCtx attempts to acquire a resource before the given context is canceled.  If the resource
	// was acquired, this method returns nil.  Otherwise, this method returns ctx.Err().
	AcquireCtx(context.Context) error

	// TryAcquire attempts to acquire a release, returning false immediately if a resource was unavailable.
	// This method returns true if the resource was acquired.
	TryAcquire() bool

	// Release relinquishes control of a resource.  If called before a corresponding acquire method,
	// this method will likely result in a deadlock.  This method must be invoked after a successful
	// acquire in order to allow other goroutines to use the resource(s).
	//
	// Typically, this method returns a nil error.  It can return a non-nil error, as with a closeable semaphore
	// that has been closed.
	Release() error
}

Interface represents a semaphore, either binary or counting. When any acquire method is successful, Release *must* be called to return the resource to the semaphore.

func Instrument

func Instrument(s Interface, o ...InstrumentOption) Interface

Instrument decorates an existing semaphore with instrumentation. The available options allow tracking the number of resources currently acquired and the total count of failures over time. The returned Interface object will not implement Closeable, even if the decorated semaphore does.

func Mutex

func Mutex() Interface

Mutex is just syntactic sugar for New(1). The returned object is a binary semaphore.

Example
const routineCount = 5

var (
	s     = Mutex()
	wg    = new(sync.WaitGroup)
	value int
)

wg.Add(routineCount)
for i := 0; i < routineCount; i++ {
	go func() {
		defer wg.Done()
		defer s.Release()
		s.Acquire()
		value++
		fmt.Println(value)
	}()
}

wg.Wait()
Output:

1
2
3
4
5

func New

func New(count int) Interface

New constructs a semaphore with the given count. A nonpositive count will result in a panic. A count of 1 is essentially a mutex, albeit with the ability to timeout or cancel the acquisition of the lock.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL