github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/sync/waitgroup_test.go (about) 1 // Copyright 2011 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 sync_test 6 7 import ( 8 "runtime" 9 . "sync" 10 "sync/atomic" 11 "testing" 12 ) 13 14 func testWaitGroup(t *testing.T, wg1 *WaitGroup, wg2 *WaitGroup) { 15 n := 16 16 wg1.Add(n) 17 wg2.Add(n) 18 exited := make(chan bool, n) 19 for i := 0; i != n; i++ { 20 go func(i int) { 21 wg1.Done() 22 wg2.Wait() 23 exited <- true 24 }(i) 25 } 26 wg1.Wait() 27 for i := 0; i != n; i++ { 28 select { 29 case <-exited: 30 t.Fatal("WaitGroup released group too soon") 31 default: 32 } 33 wg2.Done() 34 } 35 for i := 0; i != n; i++ { 36 <-exited // Will block if barrier fails to unlock someone. 37 } 38 } 39 40 func TestWaitGroup(t *testing.T) { 41 wg1 := &WaitGroup{} 42 wg2 := &WaitGroup{} 43 44 // Run the same test a few times to ensure barrier is in a proper state. 45 for i := 0; i != 8; i++ { 46 testWaitGroup(t, wg1, wg2) 47 } 48 } 49 50 func TestWaitGroupMisuse(t *testing.T) { 51 defer func() { 52 err := recover() 53 if err != "sync: negative WaitGroup counter" { 54 t.Fatalf("Unexpected panic: %#v", err) 55 } 56 }() 57 wg := &WaitGroup{} 58 wg.Add(1) 59 wg.Done() 60 wg.Done() 61 t.Fatal("Should panic") 62 } 63 64 func BenchmarkWaitGroupUncontended(b *testing.B) { 65 type PaddedWaitGroup struct { 66 WaitGroup 67 pad [128]uint8 68 } 69 const CallsPerSched = 1000 70 procs := runtime.GOMAXPROCS(-1) 71 N := int32(b.N / CallsPerSched) 72 c := make(chan bool, procs) 73 for p := 0; p < procs; p++ { 74 go func() { 75 var wg PaddedWaitGroup 76 for atomic.AddInt32(&N, -1) >= 0 { 77 runtime.Gosched() 78 for g := 0; g < CallsPerSched; g++ { 79 wg.Add(1) 80 wg.Done() 81 wg.Wait() 82 } 83 } 84 c <- true 85 }() 86 } 87 for p := 0; p < procs; p++ { 88 <-c 89 } 90 } 91 92 func benchmarkWaitGroupAddDone(b *testing.B, localWork int) { 93 const CallsPerSched = 1000 94 procs := runtime.GOMAXPROCS(-1) 95 N := int32(b.N / CallsPerSched) 96 c := make(chan bool, procs) 97 var wg WaitGroup 98 for p := 0; p < procs; p++ { 99 go func() { 100 foo := 0 101 for atomic.AddInt32(&N, -1) >= 0 { 102 runtime.Gosched() 103 for g := 0; g < CallsPerSched; g++ { 104 wg.Add(1) 105 for i := 0; i < localWork; i++ { 106 foo *= 2 107 foo /= 2 108 } 109 wg.Done() 110 } 111 } 112 c <- foo == 42 113 }() 114 } 115 for p := 0; p < procs; p++ { 116 <-c 117 } 118 } 119 120 func BenchmarkWaitGroupAddDone(b *testing.B) { 121 benchmarkWaitGroupAddDone(b, 0) 122 } 123 124 func BenchmarkWaitGroupAddDoneWork(b *testing.B) { 125 benchmarkWaitGroupAddDone(b, 100) 126 } 127 128 func benchmarkWaitGroupWait(b *testing.B, localWork int) { 129 const CallsPerSched = 1000 130 procs := runtime.GOMAXPROCS(-1) 131 N := int32(b.N / CallsPerSched) 132 c := make(chan bool, procs) 133 var wg WaitGroup 134 wg.Add(procs) 135 for p := 0; p < procs; p++ { 136 go wg.Done() 137 } 138 for p := 0; p < procs; p++ { 139 go func() { 140 foo := 0 141 for atomic.AddInt32(&N, -1) >= 0 { 142 runtime.Gosched() 143 for g := 0; g < CallsPerSched; g++ { 144 wg.Wait() 145 for i := 0; i < localWork; i++ { 146 foo *= 2 147 foo /= 2 148 } 149 } 150 } 151 c <- foo == 42 152 }() 153 } 154 for p := 0; p < procs; p++ { 155 <-c 156 } 157 } 158 159 func BenchmarkWaitGroupWait(b *testing.B) { 160 benchmarkWaitGroupWait(b, 0) 161 } 162 163 func BenchmarkWaitGroupWaitWork(b *testing.B) { 164 benchmarkWaitGroupWait(b, 100) 165 }