本文深入探讨了 Go 语言中的并发控制机制,包括互斥锁(sync.Mutex)、原子操作(sync/atomic)以及 sync.WaitGroup 的使用。通过示例代码展示了它们在并发场景下的应用,帮助读者理解如何在 Go 中确保数据安全和正确同步。
// 互斥锁package main
import("bytes""fmt""runtime""strconv""sync")funcgoid()uint64{
b :=make([]byte,64)
b = b[:runtime.Stack(b,false)]
b = bytes.TrimPrefix(b,[]byte("goroutine "))
b = b[:bytes.IndexByte(b,' ')]
n,_:= strconv.ParseUint(string(b),10,64)return n
}funcmain(){
runtime.GOMAXPROCS(runtime.NumCPU())const taskNum =2
cnt :=uint64(0)var wg sync.WaitGroup
var mtx sync.Mutex
wg.Add(taskNum)
fmt.Printf("cnt: %p, wg: %p \n",&cnt,&wg)for i :=0; i < taskNum; i++{gofunc(id int, counter *uint64, wg *sync.WaitGroup, mtx *sync.Mutex){defer wg.Done()for c :=0; c <10; c++{
mtx.Lock()*counter +=1
x :=*counter
mtx.Unlock()
fmt.Printf("goid: %d, cnt: %d, wg: %p\n",goid(), x, wg)
runtime.Gosched()}}(i,&cnt,&wg,&mtx)}
wg.Wait()
fmt.Println("end")}
// 原子操作package main
import("bytes""fmt""runtime""strconv""sync""sync/atomic""time")funcgoid()uint64{
b :=make([]byte,64)
b = b[:runtime.Stack(b,false)]
b = bytes.TrimPrefix(b,[]byte("goroutine "))
b = b[:bytes.IndexByte(b,' ')]
n,_:= strconv.ParseUint(string(b),10,64)return n
}funcmain(){
runtime.GOMAXPROCS(runtime.NumCPU())const taskNum =2
cnt :=uint64(0)var wg sync.WaitGroup
wg.Add(taskNum)
fmt.Printf("cnt: %p, wg: %p \n",&cnt,&wg)for i :=0; i < taskNum; i++{gofunc(wg *sync.WaitGroup, id int, cnt *uint64){defer wg.Done()for{
fmt.Printf("goid: %d work \n",goid())if atomic.LoadUint64(cnt)==1{
fmt.Printf("goid: %d break \n",goid())break}
time.Sleep(time.Second *1)
runtime.Gosched()}}(&wg, i,&cnt)}
time.Sleep(time.Second *10)
atomic.StoreUint64(&cnt,1)
wg.Wait()
fmt.Println("end")}
// WaitGroup和atomic.AddUint64package main
import("bytes""fmt""runtime""strconv""sync""sync/atomic")funcgoid()uint64{
b :=make([]byte,64)
b = b[:runtime.Stack(b,false)]
b = bytes.TrimPrefix(b,[]byte("goroutine "))
b = b[:bytes.IndexByte(b,' ')]
n,_:= strconv.ParseUint(string(b),10,64)return n
}funcmain(){
runtime.GOMAXPROCS(runtime.NumCPU())const taskNum =5
cnt :=uint64(0)var wg sync.WaitGroup
wg.Add(taskNum)
fmt.Printf("cnt: %p, wg: %p \n",&cnt,&wg)for i :=0; i < taskNum; i++{gofunc(id int, counter *uint64, wg *sync.WaitGroup){defer wg.Done()for c :=0; c <10; c++{
x := atomic.AddUint64(counter,1)
fmt.Printf("goid: %d, cnt: %d, wg: %p\n",goid(), x, wg)
runtime.Gosched()}}(i,&cnt,&wg)}
wg.Wait()
fmt.Println("end")}
// sync.WaitGrouppackage main
import("bytes""fmt""runtime""strconv""sync")funcgoid()uint64{
b :=make([]byte,64)
b = b[:runtime.Stack(b,false)]
b = bytes.TrimPrefix(b,[]byte("goroutine "))
b = b[:bytes.IndexByte(b,' ')]
n,_:= strconv.ParseUint(string(b),10,64)return n
}funcmain(){
runtime.GOMAXPROCS(runtime.NumCPU())const taskNum =5var wg sync.WaitGroup
wg.Add(taskNum)
fmt.Printf("start, wg: %p \n",&wg)for i :=0; i < taskNum; i++{gofunc(wg *sync.WaitGroup, i int){defer wg.Done()
fmt.Printf("goid: %d, i: %d, wg: %p \n",goid(), i, wg)}(&wg, i)}
wg.Wait()
fmt.Println("end")}