github.com/yanyiwu/go@v0.0.0-20150106053140-03d6637dbb7f/src/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  	. "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(i int) {
    20  			wg1.Done()
    21  			wg2.Wait()
    22  			exited <- true
    23  		}(i)
    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 BenchmarkWaitGroupUncontended(b *testing.B) {
    89  	type PaddedWaitGroup struct {
    90  		WaitGroup
    91  		pad [128]uint8
    92  	}
    93  	b.RunParallel(func(pb *testing.PB) {
    94  		var wg PaddedWaitGroup
    95  		for pb.Next() {
    96  			wg.Add(1)
    97  			wg.Done()
    98  			wg.Wait()
    99  		}
   100  	})
   101  }
   102  
   103  func benchmarkWaitGroupAddDone(b *testing.B, localWork int) {
   104  	var wg WaitGroup
   105  	b.RunParallel(func(pb *testing.PB) {
   106  		foo := 0
   107  		for pb.Next() {
   108  			wg.Add(1)
   109  			for i := 0; i < localWork; i++ {
   110  				foo *= 2
   111  				foo /= 2
   112  			}
   113  			wg.Done()
   114  		}
   115  		_ = foo
   116  	})
   117  }
   118  
   119  func BenchmarkWaitGroupAddDone(b *testing.B) {
   120  	benchmarkWaitGroupAddDone(b, 0)
   121  }
   122  
   123  func BenchmarkWaitGroupAddDoneWork(b *testing.B) {
   124  	benchmarkWaitGroupAddDone(b, 100)
   125  }
   126  
   127  func benchmarkWaitGroupWait(b *testing.B, localWork int) {
   128  	var wg WaitGroup
   129  	b.RunParallel(func(pb *testing.PB) {
   130  		foo := 0
   131  		for pb.Next() {
   132  			wg.Wait()
   133  			for i := 0; i < localWork; i++ {
   134  				foo *= 2
   135  				foo /= 2
   136  			}
   137  		}
   138  		_ = foo
   139  	})
   140  }
   141  
   142  func BenchmarkWaitGroupWait(b *testing.B) {
   143  	benchmarkWaitGroupWait(b, 0)
   144  }
   145  
   146  func BenchmarkWaitGroupWaitWork(b *testing.B) {
   147  	benchmarkWaitGroupWait(b, 100)
   148  }