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 }