// 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() | |
} |