package main; import ( "sync/atomic" "fmt" "sync" ) //atomic包提供了底層的原子級內存操作 //類型共有六種:int32, int64, uint32, uint64, uintptr, unsafe.Pinter //操作共五種:增減, 比較並交換, 載入, 存儲,交換 func main() { //增減操作 var a int32; fmt.Println("a : ", a); //函數名以Add為前綴,加具體類型名 //參數一,是指針類型 //參數二,與參數一類型總是相同 //增操作 new_a := atomic.AddInt32(&a, 3); fmt.Println("new_a : ", new_a); //減操作 new_a = atomic.AddInt32(&a, -2); fmt.Println("new_a : ", new_a); //CAS(Compare And Swap)比較並交換操作 //函數名以CompareAndSwap為前綴,並具體類型名 var b int32; fmt.Println("b : ", b); //函數會先判斷參數一指向的值與參數二是否相等,如果相等,則用參數三替換參數一的值。 //最后返回是否替換成功 atomic.CompareAndSwapInt32(&b, 0, 3); fmt.Println("b : ", b); //載入操作 //當我們對某個變量進行讀取操作時,可能該變量正在被其他操作改變,或許我們讀取的是被修改了一半的數據。 //所以我們通過Load這類函數來確保我們正確的讀取 //函數名以Load為前綴,加具體類型名 var c int32; wg := sync.WaitGroup{}; //我們啟100個goroutine for i := 0; i < 100; i++ { wg.Add(1); go func() { defer wg.Done(); tmp := atomic.LoadInt32(&c); if !atomic.CompareAndSwapInt32(&c, tmp, (tmp + 1)) { fmt.Println("c 修改失敗"); } }(); } wg.Wait(); //c的值有可能不等於100,頻繁修改變量值情況下,CAS操作有可能不成功。 fmt.Println("c : ", c); //存儲操作 //與載入函數相對應,提供原子的存儲函數 //函數名以Store為前綴,加具體類型名 var d int32; fmt.Println("d : ", d); //存儲某個值時,任何CPU都不會都該值進行讀或寫操作 //存儲操作總會成功,它不關心舊值是什么,與CAS不同 atomic.StoreInt32(&d, 666); fmt.Println("d : ", d); //交換操作 //直接設置新值,返回舊值,與CAS不同,它不關心舊值。 //函數名以Swap為前綴,加具體類型名 var e int32; wg2 := sync.WaitGroup{}; //我們啟10個goroutine for i := 0; i < 10; i++ { wg2.Add(1); go func() { defer wg2.Done(); tmp := atomic.LoadInt32(&e); old := atomic.SwapInt32(&e, (tmp + 1)); fmt.Println("e old : ", old); }(); } wg2.Wait(); fmt.Println("e : ", e); }