Go-Atomic应用

atomic 操作的对象是一个地址,你需要把可寻址的变量的地址作为参数传递给方法,而不是把变量的值传递给方法。

提供的方法有:

Add

func AddInt32(addr *int32, delta int32) (new int32)
给一个地址上的内容加上值,返回新的值

CAS

func CompareAndSwapInt32(addr *int32, old, new int32)(swapped bool)
比较并替换某个地址上的值,返回成功或失败。
因此代码里常用循环,失败后再次操作

Swap

func SwapInt32(add *int32, new int32) (old int32)
不比较旧值,直接替换,返回替换的值,因此并发时每个返回的替换值是不同的。

Load

func LoadInt32(add *int32) (val int32)
取出addr地址中的值,即使在多处理器、多核、有 CPU cache 的情况下,这个操作也能保证 Load 是一个原子操作。

Store

func StoreInt32(add *int32, val int32)
把一个值存到指定的addr地址中,即使在多处理器、多核、有 CPU cache 的情况下,这个操作也能保证 Store 是一个原子操作。别的 goroutine 通过 Load 读取出来,不会看到存取了一半的值。它支持的数据类型和方法如图所示。
和Swap相比,没有返回值。

以上这些原子操作,可操作的类型包括int32 int64 uint32 uint64 unsafe.Pointer uintptr

atomic提供一种特殊的类型:Value,可以原子的存去对象类型,不能CAS和Swap,常常用在配置变更等场景中。
func(v *Value) Load(x interface{})
func(v *value) Store(x interface{})

实现一个无锁队列

package lockfree

import (
	"sync/atomic"
	"unsafe"
)

type LKQueue struct {
	head unsafe.Pointer
	tail unsafe.Pointer
}

type node struct {
	value interface{}
	next unsafe.Pointer
}

func NewLKQueue() *LKQueue {
	n := unsafe.Pointer(&node{})
	return &LKQueue{head: n, tail: n}
}

func (q *LKQueue) Enqueue(v interface{}){
	n := &node{value: v}
	for{
		tail := load(&q.tail)  // node类型
		next := load(&tail.next) // 这里可能也被赋值了

		// 尾节点未变化
		if tail == load(&q.tail) {
			if next == nil {
				if cas(&tail.next, next, n) {
					cas(&q.tail, tail, n)
					return
				}
			} else {
				cas(&q.tail, tail, next)  // 这里需要做吗?
			}
		}

		//tail.next = n;
		//n.next = nil
	}
}

func (q *LKQueue) Dequeue() interface{} {
	for{
		head := load(&q.head)
		tail := load(&q.tail)
		next := load(&head.next)
		if head == load(&q.head) { 	 //head没变
			if head == tail {
				if next == nil {
					return nil
				}
				cas(&q.tail, tail, next)
			} else {
				v := next.value
				if cas(&q.head, head, next) {
					return v
				}
			}
		}
	}
}

func load(p *unsafe.Pointer) (n *node){
	return (*node)(atomic.LoadPointer(p))
}

func cas(p *unsafe.Pointer, old, new *node) (ok bool) {
	return atomic.CompareAndSwapPointer(p, unsafe.Pointer(old), unsafe.Pointer(new))
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值