| | |
| | |
| | |
| |
|
| | package race_test |
| |
|
| | import ( |
| | "runtime" |
| | "sync" |
| | "testing" |
| | "time" |
| | ) |
| |
|
| | func TestNoRaceWaitGroup(t *testing.T) { |
| | var x int |
| | _ = x |
| | var wg sync.WaitGroup |
| | n := 1 |
| | for i := 0; i < n; i++ { |
| | wg.Add(1) |
| | j := i |
| | go func() { |
| | x = j |
| | wg.Done() |
| | }() |
| | } |
| | wg.Wait() |
| | } |
| |
|
| | func TestRaceWaitGroup(t *testing.T) { |
| | var x int |
| | _ = x |
| | var wg sync.WaitGroup |
| | n := 2 |
| | for i := 0; i < n; i++ { |
| | wg.Add(1) |
| | j := i |
| | go func() { |
| | x = j |
| | wg.Done() |
| | }() |
| | } |
| | wg.Wait() |
| | } |
| |
|
| | func TestNoRaceWaitGroup2(t *testing.T) { |
| | var x int |
| | _ = x |
| | var wg sync.WaitGroup |
| | wg.Add(1) |
| | go func() { |
| | x = 1 |
| | wg.Done() |
| | }() |
| | wg.Wait() |
| | x = 2 |
| | } |
| |
|
| | |
| | func TestRaceWaitGroupAsMutex(t *testing.T) { |
| | var x int |
| | _ = x |
| | var wg sync.WaitGroup |
| | c := make(chan bool, 2) |
| | go func() { |
| | wg.Wait() |
| | time.Sleep(100 * time.Millisecond) |
| | wg.Add(+1) |
| | x = 1 |
| | wg.Add(-1) |
| | c <- true |
| | }() |
| | go func() { |
| | wg.Wait() |
| | time.Sleep(100 * time.Millisecond) |
| | wg.Add(+1) |
| | x = 2 |
| | wg.Add(-1) |
| | c <- true |
| | }() |
| | <-c |
| | <-c |
| | } |
| |
|
| | |
| | func TestRaceWaitGroupWrongWait(t *testing.T) { |
| | c := make(chan bool, 2) |
| | var x int |
| | _ = x |
| | var wg sync.WaitGroup |
| | go func() { |
| | wg.Add(1) |
| | runtime.Gosched() |
| | x = 1 |
| | wg.Done() |
| | c <- true |
| | }() |
| | go func() { |
| | wg.Add(1) |
| | runtime.Gosched() |
| | x = 2 |
| | wg.Done() |
| | c <- true |
| | }() |
| | wg.Wait() |
| | <-c |
| | <-c |
| | } |
| |
|
| | func TestRaceWaitGroupWrongAdd(t *testing.T) { |
| | c := make(chan bool, 2) |
| | var wg sync.WaitGroup |
| | go func() { |
| | wg.Add(1) |
| | time.Sleep(100 * time.Millisecond) |
| | wg.Done() |
| | c <- true |
| | }() |
| | go func() { |
| | wg.Add(1) |
| | time.Sleep(100 * time.Millisecond) |
| | wg.Done() |
| | c <- true |
| | }() |
| | time.Sleep(50 * time.Millisecond) |
| | wg.Wait() |
| | <-c |
| | <-c |
| | } |
| |
|
| | func TestNoRaceWaitGroupMultipleWait(t *testing.T) { |
| | c := make(chan bool, 2) |
| | var wg sync.WaitGroup |
| | go func() { |
| | wg.Wait() |
| | c <- true |
| | }() |
| | go func() { |
| | wg.Wait() |
| | c <- true |
| | }() |
| | wg.Wait() |
| | <-c |
| | <-c |
| | } |
| |
|
| | func TestNoRaceWaitGroupMultipleWait2(t *testing.T) { |
| | c := make(chan bool, 2) |
| | var wg sync.WaitGroup |
| | wg.Add(2) |
| | go func() { |
| | wg.Done() |
| | wg.Wait() |
| | c <- true |
| | }() |
| | go func() { |
| | wg.Done() |
| | wg.Wait() |
| | c <- true |
| | }() |
| | wg.Wait() |
| | <-c |
| | <-c |
| | } |
| |
|
| | func TestNoRaceWaitGroupMultipleWait3(t *testing.T) { |
| | const P = 3 |
| | var data [P]int |
| | done := make(chan bool, P) |
| | var wg sync.WaitGroup |
| | wg.Add(P) |
| | for p := 0; p < P; p++ { |
| | go func(p int) { |
| | data[p] = 42 |
| | wg.Done() |
| | }(p) |
| | } |
| | for p := 0; p < P; p++ { |
| | go func() { |
| | wg.Wait() |
| | for p1 := 0; p1 < P; p1++ { |
| | _ = data[p1] |
| | } |
| | done <- true |
| | }() |
| | } |
| | for p := 0; p < P; p++ { |
| | <-done |
| | } |
| | } |
| |
|
| | |
| | func TestRaceWaitGroup2(t *testing.T) { |
| | var x int |
| | _ = x |
| | var wg sync.WaitGroup |
| | wg.Add(2) |
| | go func() { |
| | x = 1 |
| | wg.Done() |
| | }() |
| | go func() { |
| | x = 2 |
| | wg.Done() |
| | }() |
| | wg.Wait() |
| | } |
| |
|
| | func TestNoRaceWaitGroupPanicRecover(t *testing.T) { |
| | var x int |
| | _ = x |
| | var wg sync.WaitGroup |
| | defer func() { |
| | err := recover() |
| | if err != "sync: negative WaitGroup counter" { |
| | t.Fatalf("Unexpected panic: %#v", err) |
| | } |
| | x = 2 |
| | }() |
| | x = 1 |
| | wg.Add(-1) |
| | } |
| |
|
| | |
| | |
| | |
| | func TestNoRaceWaitGroupPanicRecover2(t *testing.T) { |
| | var x int |
| | _ = x |
| | var wg sync.WaitGroup |
| | ch := make(chan bool, 1) |
| | var f func() = func() { |
| | x = 2 |
| | ch <- true |
| | } |
| | go func() { |
| | defer func() { |
| | err := recover() |
| | if err != "sync: negative WaitGroup counter" { |
| | } |
| | go f() |
| | }() |
| | x = 1 |
| | wg.Add(-1) |
| | }() |
| |
|
| | <-ch |
| | } |
| |
|
| | func TestNoRaceWaitGroupTransitive(t *testing.T) { |
| | x, y := 0, 0 |
| | var wg sync.WaitGroup |
| | wg.Add(2) |
| | go func() { |
| | x = 42 |
| | wg.Done() |
| | }() |
| | go func() { |
| | time.Sleep(1e7) |
| | y = 42 |
| | wg.Done() |
| | }() |
| | wg.Wait() |
| | _ = x |
| | _ = y |
| | } |
| |
|
| | func TestNoRaceWaitGroupReuse(t *testing.T) { |
| | const P = 3 |
| | var data [P]int |
| | var wg sync.WaitGroup |
| | for try := 0; try < 3; try++ { |
| | wg.Add(P) |
| | for p := 0; p < P; p++ { |
| | go func(p int) { |
| | data[p]++ |
| | wg.Done() |
| | }(p) |
| | } |
| | wg.Wait() |
| | for p := 0; p < P; p++ { |
| | data[p]++ |
| | } |
| | } |
| | } |
| |
|
| | func TestNoRaceWaitGroupReuse2(t *testing.T) { |
| | const P = 3 |
| | var data [P]int |
| | var wg sync.WaitGroup |
| | for try := 0; try < 3; try++ { |
| | wg.Add(P) |
| | for p := 0; p < P; p++ { |
| | go func(p int) { |
| | data[p]++ |
| | wg.Done() |
| | }(p) |
| | } |
| | done := make(chan bool) |
| | go func() { |
| | wg.Wait() |
| | for p := 0; p < P; p++ { |
| | data[p]++ |
| | } |
| | done <- true |
| | }() |
| | wg.Wait() |
| | <-done |
| | for p := 0; p < P; p++ { |
| | data[p]++ |
| | } |
| | } |
| | } |
| |
|
| | func TestRaceWaitGroupReuse(t *testing.T) { |
| | const P = 3 |
| | const T = 3 |
| | done := make(chan bool, T) |
| | var wg sync.WaitGroup |
| | for try := 0; try < T; try++ { |
| | var data [P]int |
| | wg.Add(P) |
| | for p := 0; p < P; p++ { |
| | go func(p int) { |
| | time.Sleep(50 * time.Millisecond) |
| | data[p]++ |
| | wg.Done() |
| | }(p) |
| | } |
| | go func() { |
| | wg.Wait() |
| | for p := 0; p < P; p++ { |
| | data[p]++ |
| | } |
| | done <- true |
| | }() |
| | time.Sleep(100 * time.Millisecond) |
| | wg.Wait() |
| | } |
| | for try := 0; try < T; try++ { |
| | <-done |
| | } |
| | } |
| |
|
| | func TestNoRaceWaitGroupConcurrentAdd(t *testing.T) { |
| | const P = 4 |
| | waiting := make(chan bool, P) |
| | var wg sync.WaitGroup |
| | for p := 0; p < P; p++ { |
| | go func() { |
| | wg.Add(1) |
| | waiting <- true |
| | wg.Done() |
| | }() |
| | } |
| | for p := 0; p < P; p++ { |
| | <-waiting |
| | } |
| | wg.Wait() |
| | } |
| |
|