github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/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 _ = 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 }