...

Source file src/sync/waitgroup_test.go

Documentation: sync

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

View as plain text