go---sync.WaitGroup 和 sync.Once

sync.WaitGroup 是开箱即用的,也是并发安全的,一旦被真正使用后就不能被复制了。

WaitGroup 类型有三个指针方法:

  • Add:计数器加一
  • Done :计数器减一,最好挂在 defer 语句中
  • Wait:阻塞当前 goroutine,直到计数器归零
package main

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)

func main() {
	cordinateWithWaitGroup()
}

func cordinateWithWaitGroup() {
	num  := int32(0)
	fmt.Printf("The number: %d [with sync.WaitGroup]\n", num)
	var wg sync.WaitGroup
	wg.Add(2) 
	go addNum(&num, 0, wg.Done)  
	go addNum(&num, 1, wg.Done)
	wg.Wait()  
	fmt.Println("End.")
}

// 原子地增加一次 numP 所指的变量的值
func addNum(numP *int32, id int, deferFunc func()) {
	defer func() {
		deferFunc()
	}()
	for i := 0; ; i++ {
		currNum := atomic.LoadInt32(numP)
		newNum := currNum + 1
		time.Sleep(time.Millisecond * 200)
		if atomic.CompareAndSwapInt32(numP, currNum, newNum) {
			fmt.Printf("The number: %d [%d-%d]\n", newNum, id, i)
			break
		} else {
			fmt.Printf("The CAS operation failed. [%d-%d]\n", id, i)
		}
	}
}

go---sync.WaitGroup 和 sync.Once_第1张图片
sync.Onc 类型的 Do 方法只接受一个参数,该参数类型必须是 func()。

sync.Once 类型的 Do 方法只执行“首次被调用时传入的”函数。

Once 类型的类型为 unit32 的 done 字段记录 Do 方法被调用的次数,一旦调用完成,就会从 0 变成 1。

首先在临界区外判断 done 字段,成功后锁定类型为 sync.Mutex 的字段 m,再次检查 done 是否为 0,满足后再调用参数函数,并原子操作把 done 变为 1。

你可能感兴趣的:(Go语言核心36讲(郝林)笔记)