文档章节

原子操作之sync/atomic

秋风醉了
 秋风醉了
发布于 2016/08/07 16:44
字数 900
阅读 90
收藏 0

原子操作之sync/atomic

对于并发操作而言,原子操作是个非常现实的问题。典型的就是i++的问题。 当两个CPU同时对内存中的i进行读取,然后把加一之后的值放入内存中,可能两次i++的结果,这个i只增加了一次。 如何保证多CPU对同一块内存的操作是原子的。 golang中sync/atomic就是做这个使用的。

具体的原子操作在不同的操作系统中实现是不同的。比如在Intel的CPU架构机器上,主要是使用总线锁的方式实现的。 大致的意思就是当一个CPU需要操作一个内存块的时候,向总线发送一个LOCK信号,所有CPU收到这个信号后就不对这个内存块进行操作了。 等待操作的CPU执行完操作后,发送UNLOCK信号,才结束。** 在AMD的CPU架构机器上就是使用MESI一致性协议的方式来保证原子操作。** 所以我们在看atomic源码的时候,我们看到它针对不同的操作系统有不同汇编语言文件。

如果我们善用原子操作,它会比锁更为高效。

CAS

原子操作中最经典的CAS(compare-and-swap)在atomic包中是Compare开头的函数。

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)

CAS的意思是判断内存中的某个值是否等于old值,如果是的话,则赋new值给这块内存。CAS是一个方法,并不局限在CPU原子操作中。 CAS比互斥锁乐观,但是也就代表CAS是有赋值不成功的时候,调用CAS的那一方就需要处理赋值不成功的后续行为了。

这一系列的函数需要比较后再进行交换,也有不需要进行比较就进行交换的原子操作。

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)

增加或减少

对一个数值进行增加或者减少的行为也需要保证是原子的,它对应于atomic包的函数就是

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)

读取或写入

当我们要读取一个变量的时候,很有可能这个变量正在被写入,这个时候,我们就很有可能读取到写到一半的数据。 所以读取操作是需要一个原子行为的。在atomic包中就是Load开头的函数群。

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)

好了,读取我们是完成了原子性,那写入呢?也是同样的,如果有多个CPU往内存中一个数据块写入数据的时候,可能导致这个写入的数据不完整。 在atomic包对应的是Store开头的函数群。

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)

=====END=====

本文转载自:https://github.com/polaris1119/The-Golang-Standard-Library-by-Example/blob/master/chapter16/16.02.md

共有 人打赏支持
秋风醉了
粉丝 241
博文 566
码字总数 417505
作品 0
朝阳
程序员
私信 提问
C++ 11 开发中的 Atomic 原子操作

原文出处:Nicol TAO ( @nicoltao ) 原子操作在多线程开发中经常用到,比如在计数器,序列产生器等地方,这类情况下数据有并发的危险,但是用锁去保护又显得有些浪费,所以原子类型操作十分...

Nicol TAO ( @nicol_tao )
2016/10/12
0
0
聊聊原子操作那些事

原子操作,线程间交互数据最细粒度的同步操作,它可以保证线程间读写某个数值的原子性。 由于不需要加重量级的互斥锁进行同步,因此非常轻量,而且也不需要在内核间来回切换调度,效率是非常...

ruki
2016/10/01
32
0
Java CAS操作的ABA问题

CAS介绍 比较并交换(compare and swap, CAS),是原子操作的一种,可用于在多线程编程中实现不被打断的数据交换操作,从而避免多线程同时改写某一数据时由于执行顺序不确定性以及中断的不可预...

ksfzhaohui
2016/11/22
1K
4
golang在32位系统下atomic.AddUint64导致程序崩溃及解决办法

package main import ("sync/atomic""unsafe") type a struct {x unsafe.Pointery uint64} func main() {p := new(a)atomic.AddUint64(&p.y, 1)} 在32位计算机上运行改程序,会出现错误: pa......

wkh
2014/02/12
0
1
swoole-1.7.19 版本已发布,增加原子计数模块

PHP 的异步并行网络扩展 swoole1.7.19 版本已发布,此版本增加了一个新的原子计数模块,用于实现在跨进程的原子计数器。基于gcc提供的__sync系列内置CPU原子操作函数。 下载地址: http://p...

matyhtf
2015/08/31
2.3K
26

没有更多内容

加载失败,请刷新页面

加载更多

Linux下端口转发工具rinetd介绍

linux下简单好用的工具rinetd,实现端口映射/转发/重定向,针对TCP协议,不支持UDP。 官网地址 http://www.boutell.com/rinetd 里面介绍及使用齐全。 使用场景举例: 阿里云内网Redis连接问题...

ouhoo
10分钟前
1
0
Oracle学习日志-5(算数运算符,比较运算符和逻辑运算符)

因为有编程基础,所以对于这一章还是很好理解,只需要注意对NULL的运算。 操作的表格 算数运算符 查询商品名字和商品售价,并商品售价乘2 SELECT product_name,sale_price * 2 AS "sale_pri...

白话
23分钟前
1
0
搜索引擎(Lucene介绍、分词器详解)

Lucene介绍 Lucene简介 最受欢迎的java开源全文搜索引擎开发工具包。提供了完整的查询引擎和索引引擎,部分文本分词引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简...

这很耳东先生
28分钟前
0
0
quartz详细介绍

quartz常用api Scheduler 调度程序交互的主要API。 Job 希望由调度程序执行的组件实现的接口。 JobDetail 用于定义作业的实例。 JobDataMap 可以包含不限量的序列化数据,在job运行的时候可以...

大笨象会跳舞吧
28分钟前
1
0
kotlin使用jackson序列化enum

默认情况下,我们序列化与反序列化enum是它的name,事实上大部分情况下我们需要序列化的是我们自定义的value,那应该怎么做呢? 这种情况下我们就需要@JsonValue与@JsonCreator data class U...

weidedong
33分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部