rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/sync/cond_test.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  package sync_test
     5  
     6  import (
     7  	. "sync"
     8  
     9  	"runtime"
    10  	"testing"
    11  )
    12  
    13  func TestCondSignal(t *testing.T) {
    14  	var m Mutex
    15  	c := NewCond(&m)
    16  	n := 2
    17  	running := make(chan bool, n)
    18  	awake := make(chan bool, n)
    19  	for i := 0; i < n; i++ {
    20  		go func() {
    21  			m.Lock()
    22  			running <- true
    23  			c.Wait()
    24  			awake <- true
    25  			m.Unlock()
    26  		}()
    27  	}
    28  	for i := 0; i < n; i++ {
    29  		<-running // Wait for everyone to run.
    30  	}
    31  	for n > 0 {
    32  		select {
    33  		case <-awake:
    34  			t.Fatal("goroutine not asleep")
    35  		default:
    36  		}
    37  		m.Lock()
    38  		c.Signal()
    39  		m.Unlock()
    40  		<-awake // Will deadlock if no goroutine wakes up
    41  		select {
    42  		case <-awake:
    43  			t.Fatal("too many goroutines awake")
    44  		default:
    45  		}
    46  		n--
    47  	}
    48  	c.Signal()
    49  }
    50  
    51  func TestCondSignalGenerations(t *testing.T) {
    52  	var m Mutex
    53  	c := NewCond(&m)
    54  	n := 100
    55  	running := make(chan bool, n)
    56  	awake := make(chan int, n)
    57  	for i := 0; i < n; i++ {
    58  		go func(i int) {
    59  			m.Lock()
    60  			running <- true
    61  			c.Wait()
    62  			awake <- i
    63  			m.Unlock()
    64  		}(i)
    65  		if i > 0 {
    66  			a := <-awake
    67  			if a != i-1 {
    68  				t.Fatalf("wrong goroutine woke up: want %d, got %d", i-1, a)
    69  			}
    70  		}
    71  		<-running
    72  		m.Lock()
    73  		c.Signal()
    74  		m.Unlock()
    75  	}
    76  }
    77  
    78  func TestCondBroadcast(t *testing.T) {
    79  	var m Mutex
    80  	c := NewCond(&m)
    81  	n := 200
    82  	running := make(chan int, n)
    83  	awake := make(chan int, n)
    84  	exit := false
    85  	for i := 0; i < n; i++ {
    86  		go func(g int) {
    87  			m.Lock()
    88  			for !exit {
    89  				running <- g
    90  				c.Wait()
    91  				awake <- g
    92  			}
    93  			m.Unlock()
    94  		}(i)
    95  	}
    96  	for i := 0; i < n; i++ {
    97  		for i := 0; i < n; i++ {
    98  			<-running // Will deadlock unless n are running.
    99  		}
   100  		if i == n-1 {
   101  			m.Lock()
   102  			exit = true
   103  			m.Unlock()
   104  		}
   105  		select {
   106  		case <-awake:
   107  			t.Fatal("goroutine not asleep")
   108  		default:
   109  		}
   110  		m.Lock()
   111  		c.Broadcast()
   112  		m.Unlock()
   113  		seen := make([]bool, n)
   114  		for i := 0; i < n; i++ {
   115  			g := <-awake
   116  			if seen[g] {
   117  				t.Fatal("goroutine woke up twice")
   118  			}
   119  			seen[g] = true
   120  		}
   121  	}
   122  	select {
   123  	case <-running:
   124  		t.Fatal("goroutine did not exit")
   125  	default:
   126  	}
   127  	c.Broadcast()
   128  }
   129  
   130  func TestRace(t *testing.T) {
   131  	x := 0
   132  	c := NewCond(&Mutex{})
   133  	done := make(chan bool)
   134  	go func() {
   135  		c.L.Lock()
   136  		x = 1
   137  		c.Wait()
   138  		if x != 2 {
   139  			t.Fatal("want 2")
   140  		}
   141  		x = 3
   142  		c.Signal()
   143  		c.L.Unlock()
   144  		done <- true
   145  	}()
   146  	go func() {
   147  		c.L.Lock()
   148  		for {
   149  			if x == 1 {
   150  				x = 2
   151  				c.Signal()
   152  				break
   153  			}
   154  			c.L.Unlock()
   155  			runtime.Gosched()
   156  			c.L.Lock()
   157  		}
   158  		c.L.Unlock()
   159  		done <- true
   160  	}()
   161  	go func() {
   162  		c.L.Lock()
   163  		for {
   164  			if x == 2 {
   165  				c.Wait()
   166  				if x != 3 {
   167  					t.Fatal("want 3")
   168  				}
   169  				break
   170  			}
   171  			if x == 3 {
   172  				break
   173  			}
   174  			c.L.Unlock()
   175  			runtime.Gosched()
   176  			c.L.Lock()
   177  		}
   178  		c.L.Unlock()
   179  		done <- true
   180  	}()
   181  	<-done
   182  	<-done
   183  	<-done
   184  }
   185  
   186  func TestCondCopy(t *testing.T) {
   187  	defer func() {
   188  		err := recover()
   189  		if err == nil || err.(string) != "sync.Cond is copied" {
   190  			t.Fatalf("got %v, expect sync.Cond is copied", err)
   191  		}
   192  	}()
   193  	c := Cond{L: &Mutex{}}
   194  	c.Signal()
   195  	c2 := c
   196  	c2.Signal()
   197  }
   198  
   199  func BenchmarkCond1(b *testing.B) {
   200  	benchmarkCond(b, 1)
   201  }
   202  
   203  func BenchmarkCond2(b *testing.B) {
   204  	benchmarkCond(b, 2)
   205  }
   206  
   207  func BenchmarkCond4(b *testing.B) {
   208  	benchmarkCond(b, 4)
   209  }
   210  
   211  func BenchmarkCond8(b *testing.B) {
   212  	benchmarkCond(b, 8)
   213  }
   214  
   215  func BenchmarkCond16(b *testing.B) {
   216  	benchmarkCond(b, 16)
   217  }
   218  
   219  func BenchmarkCond32(b *testing.B) {
   220  	benchmarkCond(b, 32)
   221  }
   222  
   223  func benchmarkCond(b *testing.B, waiters int) {
   224  	c := NewCond(&Mutex{})
   225  	done := make(chan bool)
   226  	id := 0
   227  
   228  	for routine := 0; routine < waiters+1; routine++ {
   229  		go func() {
   230  			for i := 0; i < b.N; i++ {
   231  				c.L.Lock()
   232  				if id == -1 {
   233  					c.L.Unlock()
   234  					break
   235  				}
   236  				id++
   237  				if id == waiters+1 {
   238  					id = 0
   239  					c.Broadcast()
   240  				} else {
   241  					c.Wait()
   242  				}
   243  				c.L.Unlock()
   244  			}
   245  			c.L.Lock()
   246  			id = -1
   247  			c.Broadcast()
   248  			c.L.Unlock()
   249  			done <- true
   250  		}()
   251  	}
   252  	for routine := 0; routine < waiters+1; routine++ {
   253  		<-done
   254  	}
   255  }