// $GOROOT/src/sync/mutex.go
// A Mutex must not be copied after first use. (禁止复制首次使用后的Mutex)
// $GOROOT/src/sync/rwmutex.go
// A RWMutex must not be copied after first use.(禁止复制首次使用后的RWMutex)
// $GOROOT/src/sync/cond.go
// A Cond must not be copied after first use.(禁止复制首次使用后的Cond)
...
type signal struct{}
var ready bool
func worker(i int) {
fmt.Printf("worker %d: is working...\\n", i)
time.Sleep(1 * time.Second)
fmt.Printf("worker %d: works done\\n", i)
}
func spawnGroup(f func(i int), num int, mu *sync.Mutex) <-chan signal {
c := make(chan signal)
var wg sync.WaitGroup
for i := 0; i < num; i++ {
wg.Add(1)
go func(i int) {
for {
mu.Lock()
if !ready {
mu.Unlock()
time.Sleep(100 * time.Millisecond)
continue
}
mu.Unlock()
fmt.Printf("worker %d: start to work...\\n", i)
f(i)
wg.Done()
return
}
}(i + 1)
}
go func() {
wg.Wait()
c <- signal(struct{}{})
}()
return c
}
func main() {
fmt.Println("start a group of workers...")
mu := &sync.Mutex{}
c := spawnGroup(worker, 5, mu)
time.Sleep(5 * time.Second) // 模拟ready前的准备工作
fmt.Println("the group of workers start to work...")
mu.Lock()
ready = true
mu.Unlock()
<-c
fmt.Println("the group of workers work done!")
}
type signal struct{}
var ready bool
func worker(i int) {
fmt.Printf("worker %d: is working...\\n", i)
time.Sleep(1 * time.Second)
fmt.Printf("worker %d: works done\\n", i)
}
func spawnGroup(f func(i int), num int, groupSignal *sync.Cond) <-chan signal {
c := make(chan signal)
var wg sync.WaitGroup
for i := 0; i < num; i++ {
wg.Add(1)
go func(i int) {
groupSignal.L.Lock()
for !ready {
groupSignal.Wait()
}
groupSignal.L.Unlock()
fmt.Printf("worker %d: start to work...\\n", i)
f(i)
wg.Done()
}(i + 1)
}
go func() {
wg.Wait()
c <- signal(struct{}{})
}()
return c
}
func main() {
fmt.Println("start a group of workers...")
groupSignal := sync.NewCond(&sync.Mutex{})
c := spawnGroup(worker, 5, groupSignal)
time.Sleep(5 * time.Second) // 模拟ready前的准备工作
fmt.Println("the group of workers start to work...")
groupSignal.L.Lock()
ready = true
groupSignal.Broadcast()
groupSignal.L.Unlock()
<-c
fmt.Println("the group of workers work done!")
}
type Foo struct {
}
var once sync.Once
var instance *Foo
func GetInstance(id int) *Foo {
defer func() {
if e := recover(); e != nil {
log.Printf("goroutine-%d: caught a panic: %s", id, e)
}
}()
log.Printf("goroutine-%d: enter GetInstance\\n", id)
once.Do(func() {
instance = &Foo{}
time.Sleep(3 * time.Second)
log.Printf("goroutine-%d: the addr of instance is %p\\n", id, instance)
panic("panic in once.Do function")
})
return instance
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(i int) {
inst := GetInstance(i)
log.Printf("goroutine-%d: the addr of instance returned is %p\\n", i, inst)
wg.Done()
}(i + 1)
}
time.Sleep(5 * time.Second)
inst := GetInstance(0)
log.Printf("goroutine-0: the addr of instance returned is %p\\n", inst)
wg.Wait()
log.Printf("all goroutines exit\\n")
}