Source file src/runtime/race/testdata/waitgroup_test.go

     1  // Copyright 2012 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  
     5  package race_test
     6  
     7  import (
     8  	"runtime"
     9  	"sync"
    10  	"testing"
    11  	"time"
    12  )
    13  
    14  func TestNoRaceWaitGroup(t *testing.T) {
    15  	var x int
    16  	_ = x
    17  	var wg sync.WaitGroup
    18  	n := 1
    19  	for i := 0; i < n; i++ {
    20  		wg.Add(1)
    21  		j := i
    22  		go func() {
    23  			x = j
    24  			wg.Done()
    25  		}()
    26  	}
    27  	wg.Wait()
    28  }
    29  
    30  func TestRaceWaitGroup(t *testing.T) {
    31  	var x int
    32  	_ = x
    33  	var wg sync.WaitGroup
    34  	n := 2
    35  	for i := 0; i < n; i++ {
    36  		wg.Add(1)
    37  		j := i
    38  		go func() {
    39  			x = j
    40  			wg.Done()
    41  		}()
    42  	}
    43  	wg.Wait()
    44  }
    45  
    46  func TestNoRaceWaitGroup2(t *testing.T) {
    47  	var x int
    48  	_ = x
    49  	var wg sync.WaitGroup
    50  	wg.Add(1)
    51  	go func() {
    52  		x = 1
    53  		wg.Done()
    54  	}()
    55  	wg.Wait()
    56  	x = 2
    57  }
    58  
    59  // incrementing counter in Add and locking wg's mutex
    60  func TestRaceWaitGroupAsMutex(t *testing.T) {
    61  	var x int
    62  	_ = x
    63  	var wg sync.WaitGroup
    64  	c := make(chan bool, 2)
    65  	go func() {
    66  		wg.Wait()
    67  		time.Sleep(100 * time.Millisecond)
    68  		wg.Add(+1)
    69  		x = 1
    70  		wg.Add(-1)
    71  		c <- true
    72  	}()
    73  	go func() {
    74  		wg.Wait()
    75  		time.Sleep(100 * time.Millisecond)
    76  		wg.Add(+1)
    77  		x = 2
    78  		wg.Add(-1)
    79  		c <- true
    80  	}()
    81  	<-c
    82  	<-c
    83  }
    84  
    85  // Incorrect usage: Add is too late.
    86  func TestRaceWaitGroupWrongWait(t *testing.T) {
    87  	c := make(chan bool, 2)
    88  	var x int
    89  	_ = x
    90  	var wg sync.WaitGroup
    91  	go func() {
    92  		wg.Add(1)
    93  		runtime.Gosched()
    94  		x = 1
    95  		wg.Done()
    96  		c <- true
    97  	}()
    98  	go func() {
    99  		wg.Add(1)
   100  		runtime.Gosched()
   101  		x = 2
   102  		wg.Done()
   103  		c <- true
   104  	}()
   105  	wg.Wait()
   106  	<-c
   107  	<-c
   108  }
   109  
   110  func TestRaceWaitGroupWrongAdd(t *testing.T) {
   111  	c := make(chan bool, 2)
   112  	var wg sync.WaitGroup
   113  	go func() {
   114  		wg.Add(1)
   115  		time.Sleep(100 * time.Millisecond)
   116  		wg.Done()
   117  		c <- true
   118  	}()
   119  	go func() {
   120  		wg.Add(1)
   121  		time.Sleep(100 * time.Millisecond)
   122  		wg.Done()
   123  		c <- true
   124  	}()
   125  	time.Sleep(50 * time.Millisecond)
   126  	wg.Wait()
   127  	<-c
   128  	<-c
   129  }
   130  
   131  func TestNoRaceWaitGroupMultipleWait(t *testing.T) {
   132  	c := make(chan bool, 2)
   133  	var wg sync.WaitGroup
   134  	go func() {
   135  		wg.Wait()
   136  		c <- true
   137  	}()
   138  	go func() {
   139  		wg.Wait()
   140  		c <- true
   141  	}()
   142  	wg.Wait()
   143  	<-c
   144  	<-c
   145  }
   146  
   147  func TestNoRaceWaitGroupMultipleWait2(t *testing.T) {
   148  	c := make(chan bool, 2)
   149  	var wg sync.WaitGroup
   150  	wg.Add(2)
   151  	go func() {
   152  		wg.Done()
   153  		wg.Wait()
   154  		c <- true
   155  	}()
   156  	go func() {
   157  		wg.Done()
   158  		wg.Wait()
   159  		c <- true
   160  	}()
   161  	wg.Wait()
   162  	<-c
   163  	<-c
   164  }
   165  
   166  func TestNoRaceWaitGroupMultipleWait3(t *testing.T) {
   167  	const P = 3
   168  	var data [P]int
   169  	done := make(chan bool, P)
   170  	var wg sync.WaitGroup
   171  	wg.Add(P)
   172  	for p := 0; p < P; p++ {
   173  		go func(p int) {
   174  			data[p] = 42
   175  			wg.Done()
   176  		}(p)
   177  	}
   178  	for p := 0; p < P; p++ {
   179  		go func() {
   180  			wg.Wait()
   181  			for p1 := 0; p1 < P; p1++ {
   182  				_ = data[p1]
   183  			}
   184  			done <- true
   185  		}()
   186  	}
   187  	for p := 0; p < P; p++ {
   188  		<-done
   189  	}
   190  }
   191  
   192  // Correct usage but still a race
   193  func TestRaceWaitGroup2(t *testing.T) {
   194  	var x int
   195  	_ = x
   196  	var wg sync.WaitGroup
   197  	wg.Add(2)
   198  	go func() {
   199  		x = 1
   200  		wg.Done()
   201  	}()
   202  	go func() {
   203  		x = 2
   204  		wg.Done()
   205  	}()
   206  	wg.Wait()
   207  }
   208  
   209  func TestNoRaceWaitGroupPanicRecover(t *testing.T) {
   210  	var x int
   211  	_ = x
   212  	var wg sync.WaitGroup
   213  	defer func() {
   214  		err := recover()
   215  		if err != "sync: negative WaitGroup counter" {
   216  			t.Fatalf("Unexpected panic: %#v", err)
   217  		}
   218  		x = 2
   219  	}()
   220  	x = 1
   221  	wg.Add(-1)
   222  }
   223  
   224  // TODO: this is actually a panic-synchronization test, not a
   225  // WaitGroup test. Move it to another *_test file
   226  // Is it possible to get a race by synchronization via panic?
   227  func TestNoRaceWaitGroupPanicRecover2(t *testing.T) {
   228  	var x int
   229  	_ = x
   230  	var wg sync.WaitGroup
   231  	ch := make(chan bool, 1)
   232  	var f func() = func() {
   233  		x = 2
   234  		ch <- true
   235  	}
   236  	go func() {
   237  		defer func() {
   238  			err := recover()
   239  			if err != "sync: negative WaitGroup counter" {
   240  			}
   241  			go f()
   242  		}()
   243  		x = 1
   244  		wg.Add(-1)
   245  	}()
   246  
   247  	<-ch
   248  }
   249  
   250  func TestNoRaceWaitGroupTransitive(t *testing.T) {
   251  	x, y := 0, 0
   252  	var wg sync.WaitGroup
   253  	wg.Add(2)
   254  	go func() {
   255  		x = 42
   256  		wg.Done()
   257  	}()
   258  	go func() {
   259  		time.Sleep(1e7)
   260  		y = 42
   261  		wg.Done()
   262  	}()
   263  	wg.Wait()
   264  	_ = x
   265  	_ = y
   266  }
   267  
   268  func TestNoRaceWaitGroupReuse(t *testing.T) {
   269  	const P = 3
   270  	var data [P]int
   271  	var wg sync.WaitGroup
   272  	for try := 0; try < 3; try++ {
   273  		wg.Add(P)
   274  		for p := 0; p < P; p++ {
   275  			go func(p int) {
   276  				data[p]++
   277  				wg.Done()
   278  			}(p)
   279  		}
   280  		wg.Wait()
   281  		for p := 0; p < P; p++ {
   282  			data[p]++
   283  		}
   284  	}
   285  }
   286  
   287  func TestNoRaceWaitGroupReuse2(t *testing.T) {
   288  	const P = 3
   289  	var data [P]int
   290  	var wg sync.WaitGroup
   291  	for try := 0; try < 3; try++ {
   292  		wg.Add(P)
   293  		for p := 0; p < P; p++ {
   294  			go func(p int) {
   295  				data[p]++
   296  				wg.Done()
   297  			}(p)
   298  		}
   299  		done := make(chan bool)
   300  		go func() {
   301  			wg.Wait()
   302  			for p := 0; p < P; p++ {
   303  				data[p]++
   304  			}
   305  			done <- true
   306  		}()
   307  		wg.Wait()
   308  		<-done
   309  		for p := 0; p < P; p++ {
   310  			data[p]++
   311  		}
   312  	}
   313  }
   314  
   315  func TestRaceWaitGroupReuse(t *testing.T) {
   316  	const P = 3
   317  	const T = 3
   318  	done := make(chan bool, T)
   319  	var wg sync.WaitGroup
   320  	for try := 0; try < T; try++ {
   321  		var data [P]int
   322  		wg.Add(P)
   323  		for p := 0; p < P; p++ {
   324  			go func(p int) {
   325  				time.Sleep(50 * time.Millisecond)
   326  				data[p]++
   327  				wg.Done()
   328  			}(p)
   329  		}
   330  		go func() {
   331  			wg.Wait()
   332  			for p := 0; p < P; p++ {
   333  				data[p]++
   334  			}
   335  			done <- true
   336  		}()
   337  		time.Sleep(100 * time.Millisecond)
   338  		wg.Wait()
   339  	}
   340  	for try := 0; try < T; try++ {
   341  		<-done
   342  	}
   343  }
   344  
   345  func TestNoRaceWaitGroupConcurrentAdd(t *testing.T) {
   346  	const P = 4
   347  	waiting := make(chan bool, P)
   348  	var wg sync.WaitGroup
   349  	for p := 0; p < P; p++ {
   350  		go func() {
   351  			wg.Add(1)
   352  			waiting <- true
   353  			wg.Done()
   354  		}()
   355  	}
   356  	for p := 0; p < P; p++ {
   357  		<-waiting
   358  	}
   359  	wg.Wait()
   360  }
   361  

View as plain text