diff --git a/README.md b/README.md index abc0113..a5e40c4 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ __Synchronization Patterns__: | [Lock/Mutex](mutex/mutex.go) | Enforces mutual exclusion limit on a resource to gain exclusive access | | [Monitor](monitor.go) | Combination of mutex and condition variable patterns | | [Read-Write Lock](read_write_lock.go) | Allows parallel read access, but only exclusive access on write operations to a resource | -| [Semaphore](semaphore/semaphore.go) | Allows controlling access to a common resource | +| [Semaphore](synchronization/semaphore.md) | Allows controlling access to a common resource | __Concurrency Patterns__: diff --git a/semaphore/semaphore_test.go b/semaphore/semaphore_test.go deleted file mode 100644 index 0ca2226..0000000 --- a/semaphore/semaphore_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package semaphore_test - -import ( - "testing" - "time" - - "github.com/tmrts/go-patterns/semaphore" -) - -func TestCreatesSemaphore(t *testing.T) { - tickets, timeout := 1, 3*time.Second - s := semaphore.New(tickets, timeout) - - if err := s.Acquire(); err != nil { - t.Errorf("semaphore.Acquire() got errors %s", err) - } - - if err := s.Release(); err != nil { - t.Errorf("semaphore.Release() got errors %s", err) - } -} - -func TestCreatesNonBlockingSemaphore(t *testing.T) { - tickets, timeout := 0, 0 - s := semaphore.New(tickets, timeout) - - if err := s.Acquire(); err != semaphore.ErrIllegalRelease { - t.Errorf("non-blocking semaphore.Acquire() expected error %s got %s", semaphore.ErrIllegalRelease, err) - } -} diff --git a/semaphore/semaphore.go b/synchronization/semaphore.md similarity index 50% rename from semaphore/semaphore.go rename to synchronization/semaphore.md index 585cd11..85c7109 100644 --- a/semaphore/semaphore.go +++ b/synchronization/semaphore.md @@ -1,17 +1,17 @@ -package semaphore +# Semaphore Pattern +A semaphore is a synchronization pattern/primitive that imposes mutual exclusion on a limited number of resources. -import ( - "errors" - "time" -) +## Implementation + +```go +package semaphore var ( ErrNoTickets = errors.New("semaphore: could not aquire semaphore") ErrIllegalRelease = errors.New("semaphore: can't release the semaphore without acquiring it first") ) -// Interface, typically a type, that satisfies semaphore.Interface -// can be acquired and released. +// Interface contains the behavior of a semaphore that can be acquired and/or released. type Interface interface { Acquire() error Release() error @@ -48,3 +48,37 @@ func New(tickets int, timeout time.Duration) Interface { timeout: timeout, } } +``` + +## Usage +### Semaphore with Timeouts + +```go +tickets, timeout := 1, 3*time.Second +s := semaphore.New(tickets, timeout) + +if err := s.Acquire(); err != nil { + panic(err) +} + +// Do important work + +if err := s.Release(); err != nil { + panic(err) +} +``` +### Semaphore without Timeouts (Non-Blocking) + +```go +tickets, timeout := 0, 0 +s := semaphore.New(tickets, timeout) + +if err := s.Acquire(); err != nil { + if err != semaphore.ErrNoTickets { + panic(err) + } + + // No tickets left, can't work :( + os.Exit(1) +} +```