├── .gitignore ├── lunch ├── atomic_reactor.go ├── atomic_reactor_2.go └── lunch.go ├── queue └── queue.go ├── rendezvous ├── rendezvous.go ├── rendezvous_channels.go ├── rendezvous_many.go └── rendezvous_many_channels.go ├── semaphore └── semaphore.go └── turnstile └── turnstile.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /lunch/atomic_reactor.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | type Signal struct{} 11 | 12 | func eatLunch(name string) { 13 | fmt.Println(name, "started having lunch") 14 | time.Sleep(time.Duration(30+rand.Intn(30)) * 10 * time.Millisecond) 15 | fmt.Println(name, "finished having lunch") 16 | } 17 | 18 | func alice(ch chan Signal) { 19 | <-ch 20 | eatLunch("Alice") 21 | ch <- Signal{} 22 | } 23 | 24 | func bob(ch chan Signal) { 25 | <-ch 26 | eatLunch("Bob") 27 | ch <- Signal{} 28 | } 29 | 30 | func goWg(wg *sync.WaitGroup, f func()) { 31 | wg.Add(1) 32 | go func() { 33 | f() 34 | wg.Done() 35 | }() 36 | } 37 | 38 | func main() { 39 | wg := &sync.WaitGroup{} 40 | defer wg.Wait() 41 | 42 | ch := make(chan Signal, 1) 43 | ch <- Signal{} 44 | 45 | goWg(wg, func() { alice(ch) }) 46 | 47 | goWg(wg, func() { bob(ch) }) 48 | } 49 | -------------------------------------------------------------------------------- /lunch/atomic_reactor_2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | func eatLunch(name string) { 11 | fmt.Println(name, "started having lunch") 12 | time.Sleep(time.Duration(30+rand.Intn(30)) * 10 * time.Millisecond) 13 | fmt.Println(name, "finished having lunch") 14 | } 15 | 16 | func alice(l sync.Locker) { 17 | l.Lock() 18 | eatLunch("Alice") 19 | l.Unlock() 20 | } 21 | 22 | func bob(l sync.Locker) { 23 | l.Lock() 24 | eatLunch("Bob") 25 | l.Unlock() 26 | } 27 | 28 | func goWg(wg *sync.WaitGroup, f func()) { 29 | wg.Add(1) 30 | go func() { 31 | f() 32 | wg.Done() 33 | }() 34 | } 35 | 36 | func main() { 37 | wg := &sync.WaitGroup{} 38 | defer wg.Wait() 39 | 40 | l := &sync.Mutex{} 41 | 42 | goWg(wg, func() { alice(l) }) 43 | 44 | goWg(wg, func() { bob(l) }) 45 | } 46 | -------------------------------------------------------------------------------- /lunch/lunch.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | type Signal struct{} 11 | 12 | func eatLunch(name string) { 13 | fmt.Println(name, "started having lunch") 14 | time.Sleep(time.Duration(30+rand.Intn(30)) * 10 * time.Millisecond) 15 | fmt.Println(name, "finished having lunch") 16 | } 17 | 18 | func alice(ch chan<- Signal) { 19 | eatLunch("Alice") 20 | ch <- Signal{} 21 | } 22 | 23 | func bob(ch <-chan Signal) { 24 | <-ch 25 | eatLunch("Bob") 26 | } 27 | 28 | func goWg(wg *sync.WaitGroup, f func()) { 29 | wg.Add(1) 30 | go func() { 31 | f() 32 | wg.Done() 33 | }() 34 | } 35 | 36 | func main() { 37 | wg := &sync.WaitGroup{} 38 | defer wg.Wait() 39 | 40 | ch := make(chan Signal) 41 | 42 | goWg(wg, func() { alice(ch) }) 43 | 44 | goWg(wg, func() { bob(ch) }) 45 | } 46 | -------------------------------------------------------------------------------- /queue/queue.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | type DanceStep struct { 10 | data string 11 | } 12 | 13 | func leader(name string, queue chan<- chan DanceStep) { 14 | ch := make(chan DanceStep) 15 | queue <- ch 16 | for i := 0; i < 5; i++ { 17 | time.Sleep(50 * time.Millisecond) 18 | ch <- DanceStep{data: fmt.Sprintf("%s in step %d", name, i)} 19 | } 20 | close(ch) 21 | } 22 | 23 | func follower(name string, queue <-chan chan DanceStep) { 24 | ch := <-queue 25 | for s := range ch { 26 | fmt.Printf("%s following %s\n", name, s.data) 27 | } 28 | } 29 | 30 | func goWg(wg *sync.WaitGroup, f func()) { 31 | wg.Add(1) 32 | go func() { 33 | f() 34 | wg.Done() 35 | }() 36 | } 37 | 38 | func main() { 39 | wg := &sync.WaitGroup{} 40 | 41 | N := 4 42 | 43 | queue := make(chan chan DanceStep) 44 | 45 | for i := 0; i < N; i++ { 46 | name := string('a' + i) 47 | goWg(wg, func() { leader("l"+name, queue) }) 48 | goWg(wg, func() { follower("f"+name, queue) }) 49 | } 50 | 51 | wg.Wait() 52 | } 53 | -------------------------------------------------------------------------------- /rendezvous/rendezvous.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func worker(name string, rendezvous *sync.WaitGroup) { 9 | fmt.Printf("%s%d\n", name, 1) 10 | rendezvous.Done() 11 | rendezvous.Wait() 12 | fmt.Printf("%s%d\n", name, 2) 13 | } 14 | 15 | func goWg(wg *sync.WaitGroup, f func()) { 16 | wg.Add(1) 17 | go func() { 18 | f() 19 | wg.Done() 20 | }() 21 | } 22 | 23 | func main() { 24 | wg := &sync.WaitGroup{} 25 | defer wg.Wait() 26 | 27 | rendezvous := &sync.WaitGroup{} 28 | rendezvous.Add(2) 29 | 30 | goWg(wg, func() { worker("a", rendezvous) }) 31 | goWg(wg, func() { worker("b", rendezvous) }) 32 | } 33 | -------------------------------------------------------------------------------- /rendezvous/rendezvous_channels.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | type Signal struct{} 9 | 10 | func worker(name string, ready, wait chan Signal) { 11 | fmt.Printf("%s%d\n", name, 1) 12 | ready <- Signal{} 13 | <-wait 14 | fmt.Printf("%s%d\n", name, 2) 15 | } 16 | 17 | func goWg(wg *sync.WaitGroup, f func()) { 18 | wg.Add(1) 19 | go func() { 20 | f() 21 | wg.Done() 22 | }() 23 | } 24 | 25 | func main() { 26 | wg := &sync.WaitGroup{} 27 | defer wg.Wait() 28 | 29 | aReady := make(chan Signal, 1) 30 | bReady := make(chan Signal, 1) 31 | 32 | goWg(wg, func() { worker("a", aReady, bReady) }) 33 | goWg(wg, func() { worker("b", bReady, aReady) }) 34 | } 35 | -------------------------------------------------------------------------------- /rendezvous/rendezvous_many.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func worker(name string, rendezvous *sync.WaitGroup) { 9 | fmt.Printf("%s%d\n", name, 1) 10 | rendezvous.Done() 11 | rendezvous.Wait() 12 | fmt.Printf("%s%d\n", name, 2) 13 | } 14 | 15 | func goWg(wg *sync.WaitGroup, f func()) { 16 | wg.Add(1) 17 | go func() { 18 | f() 19 | wg.Done() 20 | }() 21 | } 22 | 23 | func main() { 24 | wg := &sync.WaitGroup{} 25 | defer wg.Wait() 26 | 27 | rendezvous := &sync.WaitGroup{} 28 | 29 | N := 10 30 | rendezvous.Add(N) 31 | 32 | for i := 0; i < N; i++ { 33 | name := string('a' + i) 34 | goWg(wg, func() { f(name, rendezvous) }) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /rendezvous/rendezvous_many_channels.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | type Signal struct{} 9 | 10 | func worker(name string, ready, wait chan Signal) { 11 | fmt.Printf("%s%d\n", name, 1) 12 | ready <- Signal{} 13 | <-wait 14 | fmt.Printf("%s%d\n", name, 2) 15 | } 16 | 17 | func helper(N int, ready, wait chan Signal) { 18 | for i := N; i > 0; i-- { 19 | <-ready 20 | } 21 | for i := N; i > 0; i-- { 22 | wait <- Signal{} 23 | } 24 | } 25 | 26 | func goWg(wg *sync.WaitGroup, f func()) { 27 | wg.Add(1) 28 | go func() { 29 | f() 30 | wg.Done() 31 | }() 32 | } 33 | 34 | func main() { 35 | wg := &sync.WaitGroup{} 36 | defer wg.Wait() 37 | 38 | N := 10 39 | ready := make(chan Signal) 40 | wait := make(chan Signal) 41 | 42 | for i := 0; i < N; i++ { 43 | name := string('a' + i) 44 | goWg(wg, func() { worker(name, ready, wait) }) 45 | } 46 | 47 | goWg(wg, func() { helper(N, ready, wait) }) 48 | } 49 | -------------------------------------------------------------------------------- /semaphore/semaphore.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "sync/atomic" 7 | ) 8 | 9 | type Semaphore interface { 10 | decrement() 11 | increment() 12 | } 13 | 14 | type SyncSemaphore struct { 15 | n int32 16 | c *sync.Cond 17 | } 18 | 19 | func NewSyncSemaphore(N int32) Semaphore { 20 | return &SyncSemaphore{ 21 | n: N, 22 | c: sync.NewCond(new(sync.Mutex)), 23 | } 24 | } 25 | 26 | func (s *SyncSemaphore) decrement() { 27 | s.c.L.Lock() 28 | for s.n <= 0 { 29 | s.c.Wait() 30 | } 31 | s.n-- 32 | s.c.L.Unlock() 33 | } 34 | 35 | func (s *SyncSemaphore) increment() { 36 | s.c.L.Lock() 37 | s.n++ 38 | s.c.L.Unlock() 39 | s.c.Signal() 40 | } 41 | 42 | type ChSemaphore chan struct{} 43 | 44 | func NewChSemaphore(N int32) Semaphore { 45 | s := ChSemaphore(make(chan struct{}, N)) 46 | for i := N; i > 0; i-- { 47 | s.increment() 48 | } 49 | return s 50 | } 51 | 52 | func (s ChSemaphore) decrement() { 53 | <-s 54 | } 55 | 56 | func (s ChSemaphore) increment() { 57 | s <- struct{}{} 58 | } 59 | 60 | func worker(s Semaphore, n *int32, stop int32, name string) { 61 | for done := false; !done; { 62 | s.decrement() 63 | if m := atomic.AddInt32(n, 1); m <= stop { 64 | fmt.Println(name, m) 65 | } else { 66 | done = true 67 | } 68 | s.increment() 69 | } 70 | } 71 | 72 | func main() { 73 | wg := &sync.WaitGroup{} 74 | 75 | N := 10 76 | s := NewChSemaphore(int32(N)) 77 | n := new(int32) 78 | 79 | for i := 0; i < 2*N; i++ { 80 | name := string('a' + i) 81 | goWg(wg, func() { 82 | worker(s, n, 1000000, name) 83 | }) 84 | } 85 | 86 | wg.Wait() 87 | } 88 | 89 | func goWg(wg *sync.WaitGroup, f func()) { 90 | wg.Add(1) 91 | go func() { 92 | f() 93 | wg.Done() 94 | }() 95 | } 96 | -------------------------------------------------------------------------------- /turnstile/turnstile.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | type Signal struct{} 9 | 10 | type Barrier struct { 11 | ready chan Signal 12 | wait chan Signal 13 | done chan struct{} 14 | } 15 | 16 | func (b Barrier) Join() { 17 | b.ready <- Signal{} 18 | <-b.wait 19 | } 20 | 21 | func NewBarrier(N int) Barrier { 22 | ready := make(chan Signal) 23 | wait := make(chan Signal) 24 | done := make(chan struct{}) 25 | 26 | helper := func() { 27 | for { 28 | for i := N; i > 0; i-- { 29 | select { 30 | case <-ready: 31 | case <-done: 32 | close(ready) 33 | close(wait) 34 | return 35 | } 36 | } 37 | for i := N; i > 0; i-- { 38 | select { 39 | case wait <- Signal{}: 40 | case <-done: 41 | close(ready) 42 | close(wait) 43 | return 44 | } 45 | } 46 | } 47 | } 48 | 49 | go helper() 50 | 51 | return Barrier{ 52 | ready: ready, 53 | wait: wait, 54 | done: done, 55 | } 56 | } 57 | 58 | func (b Barrier) Done() { 59 | close(b.done) 60 | } 61 | 62 | func worker(name string, N int, b1, b2 Barrier) { 63 | for i := N; i > 0; i-- { 64 | fmt.Printf("Worker %s entering: %d\n", name, N-i) 65 | b1.Join() 66 | fmt.Printf("Worker %s leaving: %d\n", name, N-i) 67 | b2.Join() 68 | } 69 | } 70 | 71 | func goWg(wg *sync.WaitGroup, f func()) { 72 | wg.Add(1) 73 | go func() { 74 | f() 75 | wg.Done() 76 | }() 77 | } 78 | 79 | func main() { 80 | wg := &sync.WaitGroup{} 81 | 82 | N, M := 10, 5 83 | 84 | b1 := NewBarrier(N) 85 | b2 := NewBarrier(N) 86 | 87 | for i := 0; i < N; i++ { 88 | name := string('a' + i) 89 | goWg(wg, func() { worker(name, M, b1, b2) }) 90 | } 91 | 92 | wg.Wait() 93 | 94 | b1.Done() 95 | b2.Done() 96 | } 97 | --------------------------------------------------------------------------------