From fcdf36fbbc45137d5878a8d29a0566e4789ecdb2 Mon Sep 17 00:00:00 2001 From: "jian.han" Date: Fri, 12 Jan 2018 14:36:49 +1000 Subject: [PATCH] added sem pattern --- concurrency/semaphore/main.go | 63 +++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 concurrency/semaphore/main.go diff --git a/concurrency/semaphore/main.go b/concurrency/semaphore/main.go new file mode 100644 index 0000000..91d1b77 --- /dev/null +++ b/concurrency/semaphore/main.go @@ -0,0 +1,63 @@ +package main + +import ( + "errors" + "time" + + "github.com/davecgh/go-spew/spew" +) + +func main() { + tickets, timeout := 1, 3*time.Second + s := New(tickets, timeout) + if err := s.Aquire(); err != nil { + panic(err) + } + // do important work + spew.Dump("Test") + if err := s.Release(); err != nil { + panic(err) + } +} + +// https://github.com/tmrts/go-patterns/blob/master/synchronization/semaphore.md +var ( + ErrNoTickets = errors.New("semaphore: could not aquire semaphore") + ErrIllegalRelease = errors.New("semaphore: Can not release the semaphore without acquiring it first") +) + +type Interface interface { + Aquire() error + Release() error +} + +type implementation struct { + sem chan struct{} + timeout time.Duration +} + +func (s *implementation) Aquire() error { + select { + case s.sem <- struct{}{}: + return nil + case <-time.After(s.timeout): + return ErrNoTickets + } +} + +func (s *implementation) Release() error { + select { + case _ = <-s.sem: + return nil + case <-time.After(s.timeout): + return ErrIllegalRelease + } + return nil +} + +func New(tickets int, timeout time.Duration) Interface { + return &implementation{ + sem: make(chan struct{}, tickets), + timeout: timeout, + } +}