github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/src/runtime/race/testdata/waitgroup_test.go (about)

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