| // Copyright 2011 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package sync_test | |
| import ( | |
| . "sync" | |
| "testing" | |
| ) | |
| func TestCondSignal(t *testing.T) { | |
| var m Mutex | |
| c := NewCond(&m) | |
| n := 2 | |
| running := make(chan bool, n) | |
| awake := make(chan bool, n) | |
| for i := 0; i < n; i++ { | |
| go func() { | |
| m.Lock() | |
| running <- true | |
| c.Wait() | |
| awake <- true | |
| m.Unlock() | |
| }() | |
| } | |
| for i := 0; i < n; i++ { | |
| <-running // Wait for everyone to run. | |
| } | |
| for n > 0 { | |
| select { | |
| case <-awake: | |
| t.Fatal("goroutine not asleep") | |
| default: | |
| } | |
| m.Lock() | |
| c.Signal() | |
| m.Unlock() | |
| <-awake // Will deadlock if no goroutine wakes up | |
| select { | |
| case <-awake: | |
| t.Fatal("too many goroutines awake") | |
| default: | |
| } | |
| n-- | |
| } | |
| c.Signal() | |
| } | |
| func TestCondSignalGenerations(t *testing.T) { | |
| var m Mutex | |
| c := NewCond(&m) | |
| n := 100 | |
| running := make(chan bool, n) | |
| awake := make(chan int, n) | |
| for i := 0; i < n; i++ { | |
| go func(i int) { | |
| m.Lock() | |
| running <- true | |
| c.Wait() | |
| awake <- i | |
| m.Unlock() | |
| }(i) | |
| if i > 0 { | |
| a := <-awake | |
| if a != i-1 { | |
| t.Fatalf("wrong goroutine woke up: want %d, got %d", i-1, a) | |
| } | |
| } | |
| <-running | |
| m.Lock() | |
| c.Signal() | |
| m.Unlock() | |
| } | |
| } | |
| func TestCondBroadcast(t *testing.T) { | |
| var m Mutex | |
| c := NewCond(&m) | |
| n := 200 | |
| running := make(chan int, n) | |
| awake := make(chan int, n) | |
| exit := false | |
| for i := 0; i < n; i++ { | |
| go func(g int) { | |
| m.Lock() | |
| for !exit { | |
| running <- g | |
| c.Wait() | |
| awake <- g | |
| } | |
| m.Unlock() | |
| }(i) | |
| } | |
| for i := 0; i < n; i++ { | |
| for i := 0; i < n; i++ { | |
| <-running // Will deadlock unless n are running. | |
| } | |
| if i == n-1 { | |
| m.Lock() | |
| exit = true | |
| m.Unlock() | |
| } | |
| select { | |
| case <-awake: | |
| t.Fatal("goroutine not asleep") | |
| default: | |
| } | |
| m.Lock() | |
| c.Broadcast() | |
| m.Unlock() | |
| seen := make([]bool, n) | |
| for i := 0; i < n; i++ { | |
| g := <-awake | |
| if seen[g] { | |
| t.Fatal("goroutine woke up twice") | |
| } | |
| seen[g] = true | |
| } | |
| } | |
| select { | |
| case <-running: | |
| t.Fatal("goroutine did not exit") | |
| default: | |
| } | |
| c.Broadcast() | |
| } |