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); }