Rewrite semaphore pattern

This commit is contained in:
Tamer Tas 2016-04-15 15:09:17 +03:00
parent 51e0aeb499
commit abcdf32672
3 changed files with 42 additions and 38 deletions

View File

@ -57,7 +57,7 @@ __Synchronization Patterns__:
| [Lock/Mutex](mutex/mutex.go) | Enforces mutual exclusion limit on a resource to gain exclusive access | | [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 | | [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 | | [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__: __Concurrency Patterns__:

View File

@ -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)
}
}

View File

@ -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 ( ## Implementation
"errors"
"time" ```go
) package semaphore
var ( var (
ErrNoTickets = errors.New("semaphore: could not aquire semaphore") ErrNoTickets = errors.New("semaphore: could not aquire semaphore")
ErrIllegalRelease = errors.New("semaphore: can't release the semaphore without acquiring it first") ErrIllegalRelease = errors.New("semaphore: can't release the semaphore without acquiring it first")
) )
// Interface, typically a type, that satisfies semaphore.Interface // Interface contains the behavior of a semaphore that can be acquired and/or released.
// can be acquired and released.
type Interface interface { type Interface interface {
Acquire() error Acquire() error
Release() error Release() error
@ -48,3 +48,37 @@ func New(tickets int, timeout time.Duration) Interface {
timeout: timeout, 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)
}
```