github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/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  // A common WaitGroup misuse that can potentially be caught be the race detector.
   106  // For this simple case we must emulate Add() as read on &wg and Wait() as write on &wg.
   107  // However it will have false positives if there are several concurrent Wait() calls.
   108  func TestRaceFailingWaitGroupWrongAdd(t *testing.T) {
   109  	c := make(chan bool, 2)
   110  	var wg sync.WaitGroup
   111  	go func() {
   112  		wg.Add(1)
   113  		wg.Done()
   114  		c <- true
   115  	}()
   116  	go func() {
   117  		wg.Add(1)
   118  		wg.Done()
   119  		c <- true
   120  	}()
   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  // Correct usage but still a race
   162  func TestRaceWaitGroup2(t *testing.T) {
   163  	var x int
   164  	var wg sync.WaitGroup
   165  	wg.Add(2)
   166  	go func() {
   167  		x = 1
   168  		wg.Done()
   169  	}()
   170  	go func() {
   171  		x = 2
   172  		wg.Done()
   173  	}()
   174  	wg.Wait()
   175  }
   176  
   177  func TestNoRaceWaitGroupPanicRecover(t *testing.T) {
   178  	var x int
   179  	var wg sync.WaitGroup
   180  	defer func() {
   181  		err := recover()
   182  		if err != "sync: negative WaitGroup counter" {
   183  			t.Fatalf("Unexpected panic: %#v", err)
   184  		}
   185  		x = 2
   186  	}()
   187  	x = 1
   188  	wg.Add(-1)
   189  }
   190  
   191  // TODO: this is actually a panic-synchronization test, not a
   192  // WaitGroup test. Move it to another *_test file
   193  // Is it possible to get a race by synchronization via panic?
   194  func TestNoRaceWaitGroupPanicRecover2(t *testing.T) {
   195  	var x int
   196  	var wg sync.WaitGroup
   197  	ch := make(chan bool, 1)
   198  	var f func() = func() {
   199  		x = 2
   200  		ch <- true
   201  	}
   202  	go func() {
   203  		defer func() {
   204  			err := recover()
   205  			if err != "sync: negative WaitGroup counter" {
   206  			}
   207  			go f()
   208  		}()
   209  		x = 1
   210  		wg.Add(-1)
   211  	}()
   212  
   213  	<-ch
   214  }
   215  
   216  func TestNoRaceWaitGroupTransitive(t *testing.T) {
   217  	x, y := 0, 0
   218  	var wg sync.WaitGroup
   219  	wg.Add(2)
   220  	go func() {
   221  		x = 42
   222  		wg.Done()
   223  	}()
   224  	go func() {
   225  		time.Sleep(1e7)
   226  		y = 42
   227  		wg.Done()
   228  	}()
   229  	wg.Wait()
   230  	_ = x
   231  	_ = y
   232  }