前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go并发之atomic

Go并发之atomic

作者头像
灰子学技术
发布2020-06-09 15:13:18
6460
发布2020-06-09 15:13:18
举报
文章被收录于专栏:灰子学技术灰子学技术

1. atomic介绍:

sync/atomic包提供了原子操作的能力,直接有底层CPU硬件支持,因而一般要比基于操作系统API的锁方式效率高些;这些功能需要非常小心才能正确使用。 除特殊的底层应用程序外,同步更适合使用channel或sync包的功能。 通过消息共享内存; 不要通过共享内存进行通信。

英文介绍如下:

(Package atomic provides low-level atomic memory primitives useful for implementing synchronization algorithms.These functions require great care to be used correctly. Except for special, low-level applications, synchronization is better done with channels or the facilities of the sync package. Share memory by communicating; don't communicate by sharing memory.)

链接:https://golang.org/pkg/sync/atomic/

典型使用场景:

sync/once, 实现源码如下所示:

2. atomic的API介绍

2.1 对于自增和自减的操作,对应的API

  • func AddInt32(addr *int32, delta int32) (new int32)
  • func AddInt64(addr *int64, delta int64) (new int64)
  • func AddUint32(addr *uint32, delta uint32) (new uint32)
  • func AddUint64(addr *uint64, delta uint64) (new uint64)
  • func AddUintptr(addr *uintptr, delta uintptr) (new uintptr)

伪代码实现如下所示:

代码语言:javascript
复制
*addr += delta
return *addr

2.2对于比较和交换的操作,对应的API

  • func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
  • func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)
  • func CompareAndSwapPointer(addr *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)
  • func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)
  • func CompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool)
  • func CompareAndSwapUintptr(addr *uintptr, old, new uintptr) (swapped bool)

伪代码实现如下所示:

代码语言:javascript
复制
if *addr == old {
  *addr = new
  return true
}
return false

2.3 载入操作的API

  • func LoadInt32(addr *int32) (val int32)
  • func LoadInt64(addr *int64) (val int64)
  • func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
  • func LoadUint32(addr *uint32) (val uint32)
  • func LoadUint64(addr *uint64) (val uint64)
  • func LoadUintptr(addr *uintptr) (val uintptr)

伪代码实现:

代码语言:javascript
复制
 return *addr

2.4存储操作的API:

  • func StoreInt32(addr *int32, val int32)
  • func StoreInt64(addr *int64, val int64)
  • func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)
  • func StoreUint32(addr *uint32, val uint32)
  • func StoreUint64(addr *uint64, val uint64)
  • func StoreUintptr(addr *uintptr, val uintptr)

伪代码实现:

代码语言:javascript
复制
 *addr = val

2.5 对于交换操作,对应的API:

  • func SwapInt32(addr *int32, new int32) (old int32)
  • func SwapInt64(addr *int64, new int64) (old int64)
  • func SwapPointer(addr *unsafe.Pointer, new unsafe.Pointer) (old unsafe.Pointer)
  • func SwapUint32(addr *uint32, new uint32) (old uint32)
  • func SwapUint64(addr *uint64, new uint64) (old uint64)
  • func SwapUintptr(addr *uintptr, new uintptr) (old uintptr)

伪代码实现:

代码语言:javascript
复制
old = *addr
*addr = new
return old

3.例子

使用atomic的例子:

代码语言:javascript
复制
package main

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

func main() {
        var count int32
  fmt.Println("main start...")
  var wg sync.WaitGroup
  for i:=0;i<5;i++ {
    wg.Add(1)
    go func( i int){
      defer wg.Done()
      fmt.Println("goroutine:",i,"start...")
      atomic.AddInt32(&count,1)
    
      fmt.Println("goroutine:",i,"count:",count,"end...")
    }(i)
  }
  wg.Wait()
  fmt.Println("main end...")
}

输出结果:

代码语言:javascript
复制
main start...
goroutine: 4 start...
goroutine: 2 start...
goroutine: 2 count: 2 end...
goroutine: 1 start...
goroutine: 1 count: 3 end...
goroutine: 3 start...
goroutine: 3 count: 4 end...
goroutine: 4 count: 1 end...
goroutine: 0 start...
goroutine: 0 count: 5 end...
main end...

结果分析:

通过执行代码的结果,可以看出来,atomic的AddInt32函数操作是原子性的,在一个goroutine没有执行结束的时候,其他的goroutine在执行AddInt32的时候是被lock住的。

参考文档:

https://golang.org/pkg/sync/atomic/

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 灰子学技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档