美文网首页
GO原子操作(2)

GO原子操作(2)

作者: 尼桑麻 | 来源:发表于2019-03-28 01:04 被阅读0次
参数设计
func SwapInt32(addr *int32, new int32) (old int32)
func CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool)
func LoadInt32(addr *int32) (val int32)

原子操作函数的第一个参数值对应的都应该是那个被操作的值。比如,atomic.AddInt32函数的第一个参数,对应的一定是那个要被增大的整数。而且参数的类型都是要求是指针类型。*int32。
因为原子操作函数需要的是被操作值的指针,而不是这个值本身;被传入函数的参数值都会被复制,像这种基本类型的值一旦被传入函数,就已经与函数外的那个值毫无关系了所以,传入值本身没有任何意义。unsafe.Pointer类型虽然是指针类型,但是那些原子操作函数要操作的是这个指针值,而不是它指向的那个值,所以需要的仍然是指向这个指针值的指针。
只要原子操作函数拿到了被操作值的指针,就可以定位到存储该值的内存地址。只有这样,它们才能够通过底层的指令,准确地操作这个内存地址上的数据。

原子减法

atomic只提供了add相关的方法,并没有提供减法。但是atomic.AddInt32函数的第二个参数代表差量,它的类型是int32,是有符号的。如果我们想做原子减法,那么把这个差量设置为负整数就可以了。
无符号类型如:uint32可以下方法转化:
方法一:

uint32(int32(-N))

方法二:

^uint32(-N-1))

其中的N代表由负整数表示的差量。

交换与比较并交换

交换(swap)把新值赋给变量,并返回变量的旧值
比较并交换(compare and swap,简称CAS)是有条件的交换操作,只有在条件满足的情况下才会进行值的交换。在进行CAS操作的时候,函数会先判断被操作变量的当前值,是否与我们预期的旧值相等。如果相等,它就把新值赋给该变量,并返回true以表明交换操作已进行;否则就忽略交换操作,并返回false。

CAS操作并不是单一的操作,而是一种操作组合。应用要更广泛一些,如自旋锁

for {
 if atomic.CompareAndSwapInt32(&num2, 10, 0) {
  fmt.Println("The second number has gone to zero.")
  break
 }
 time.Sleep(time.Millisecond * 500)
}

网上也有一些人用CAS做无锁编程所谓无锁编程只是将多条指令合并成了一条指令形成一个逻辑完备的最小单元,通过兼容CPU指令执行逻辑形成的一种多线程编程模型

载入与存储

载入Load 原子性的读取一个变量的值,确保在不会读到被修改到一半的值
存储Store原子地存储某个值的过程中,任何CPU都不会进行针对同一个值的读或写操作

思考

问题1:为什么不设计比较(compare)如果设计了比较(compare) ,在一段代码中, 我们先 比较(compare) 得出结果后再 交换(swap)。将CAS操作分成两步走还是原子是否安全?

答案肯定是不安全,compare 是原子的 swap 是原子,单不代表这两的组合是原子的。不设计compare原因应该是意义不大,CAS操作本身也可以实现compare,而且compare后往往还需跟其他的操作,swap通常是最尝被使用的。

问题 2:假设我已经保证了对一个变量的写操作都是原子操作,比如:加或减、存储、交换等等,那我对它进行读操作的时候,还有必要使用原子操作吗?

答案是很有必要其中的道理你可以对照一下读写锁。为什么在读写锁保护下的写操作和读操作之间是互斥的?这是为了防止读操作读到没有被修改完的值,对吗?
如果写操作还没有进行完,读操作就来读了,那么就只能读到仅修改了一部分的值。这显然破坏了值的完整性,读出来的值也是完全错误的。所以,一旦你决定了要对一个共享资源进行保护,那就要做到完全的保护。不完全的保护基本上与不保护没有什么区别

相关文章

  • Go语言——原子操作

    Go语言——原子操作 参考: 《Go并发编程实战(第2版)》 Background 原子操作即执行过程不能被中断的...

  • GO原子操作(2)

    参数设计 原子操作函数的第一个参数值对应的都应该是那个被操作的值。比如,atomic.AddInt32函数的第一个...

  • Go 原子操作

    本文讲解 golang 中 sync.atomic 的常见操作 atomic 提供的原子操作能够确保任一时刻只有一...

  • Go语言 原子操作

    原子操作就是不可中断的操作,外界是看不到原子操作的中间状态,要么看到原子操作已经完成,要么看到原子操作已经结束。在...

  • GO原子操作(1)

    读写锁是互斥锁的优化,读写锁对共享资源的写操作和读操作则区别看待,并消除了读操作之间的互斥。条件变量主要是用于协调...

  • Go - atomic包使用及atomic.Value源码分析

    1. Go中的原子操作 原子性:一个或多个操作在CPU的执行过程中不被中断的特性,称为原子性。这些操作对外表现成一...

  • 原子类与原子操作 2022-05-05

    go变量原子操作最简单的方式就是给变量配一把锁,然后在操作这个变量的方法中都加锁放锁 如【原子int】:

  • doc.go

    概述 doc.go是包atomic的提供低级原子操作的实现,对于实现同步算法很有用包含的原子操作有5种 增或减 比...

  • golang sync.once解析

    实现原理(当前代码版本go version go1.11.4 ) 1.atomic 原子操作计数器,用于记录此On...

  • go 中的 原子操作

    Go语言中提供的原子操作都是非侵入式的,在标准库代码包sync/atomic中提供了相关的原子函数。 增或减 原子...

网友评论

      本文标题:GO原子操作(2)

      本文链接:https://www.haomeiwen.com/subject/fsaxbqtx.html