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 }