锁、无锁、多处理器编程——2.原子操作

原子操作

原子操作是不可分割的操作,在执行完毕时它不会被任何事件中断,原子操作是多数无锁编程的基本前提。

内核atomic_*系列

atomic是原子的意思,意味"不可分割"的整体。在Linux kernel中有一类atomic操作API。这些操作对用户而言是原子执行的,在一个CPU上执行过程中,不会被其他CPU打断。最常见的操作是原子读改写,简称RMW。
原子操作需要硬件的支持,查看内核源码中的atomic_*函数,最终都是采用汇编执行,通过锁内存总线、内存屏障等方式来实现的。下一章会以CAS方法(例x86指令cmpxchgl)来举例说明。
原子操作主要用于实现资源计数,很多引用计数就是通过原子操作实现的。原子类型定义如下:

typedef struct { volatile int counter; } atomic_t;
  volatile修饰字段告诉gcc不要对该类型的数据做优化处理。
  对它的访问都是对内存的访问,而不是对寄存器的访问。 

原子操作API包括:

atomic_read(atomic_t * v);
  该函数对原子类型的变量进行原子读操作,它返回原子类型的变量v的值。 

atomic_set(atomic_t * v, int i);
  该函数设置原子类型的变量v的值为i。 

void atomic_add(int i, atomic_t *v);
  该函数给原子类型的变量v增加值i。 

atomic_sub(int i, atomic_t *v);
  该函数从原子类型的变量v中减去i。 

int atomic_sub_and_test(int i, atomic_t *v);
  该函数从原子类型的变量v中减去i,并判断结果是否为0,如果为0,返回真,否则返回假。 

void atomic_inc(atomic_t *v);
  该函数对原子类型变量v原子地增加1。 

void atomic_dec(atomic_t *v);
  该函数对原子类型的变量v原子地减1。 

int atomic_dec_and_test(atomic_t *v);
  该函数对原子类型的变量v原子地减1,并判断结果是否为0,如果为0,返回真,否则返回假。 

int atomic_inc_and_test(atomic_t *v);
  该函数对原子类型的变量v原子地增加1,并判断结果是否为0,如果为0,返回真,否则返回假。 

int atomic_add_negative(int i, atomic_t *v);
  该函数对原子类型的变量v原子地增加I,并判断结果是否为负数,如果是,返回真,否则返回假。 

int atomic_add_return(int i, atomic_t *v);
  该函数对原子类型的变量v原子地增加i,并且返回指向v的指针。 

int atomic_sub_return(int i, atomic_t *v);
  该函数从原子类型的变量v中减去i,并且返回指向v的指针。 

int atomic_inc_return(atomic_t * v);
  该函数对原子类型的变量v原子地增加1并且返回指向v的指针。 

int atomic_dec_return(atomic_t * v);
  该函数对原子类型的变量v原子地减1并且返回指向v的指针。

gcc中的__sync_*系列原子操作

gcc内置的__sync_*函数提供了加减和逻辑运算的原子操作,一共有十二个函数

type __sync_fetch_and_add (type *ptr, typevalue);
type __sync_fetch_and_sub (type *ptr, type value);
type __sync_fetch_and_or (type *ptr, type value);
type __sync_fetch_and_and (type *ptr, type value);
type __sync_fetch_and_xor (type *ptr, type value);
type __sync_fetch_and_nand (type *ptr, type value);
type __sync_add_and_fetch (type *ptr, typevalue);
type __sync_sub_and_fetch (type *ptr, type value);
type __sync_or_and_fetch (type *ptr, type value);
type __sync_and_and_fetch (type *ptr, type value);
type __sync_xor_and_fetch (type *ptr, type value);
type __sync_nand_and_fetch (type *ptr, type value);

type可以是1,2,4或8字节长度的int类型,即:

int8_t / uint8_t
int16_t / uint16_t
int32_t / uint32_t
int64_t / uint64_t

处理器如何实现原子操作

(1)总线锁Bus Lock:使用处理器提供一个LOCK#信号,当一个处理器在总线上输出此信号的时候,其他处理器的请求将被阻塞,那么该处理器可以独占使用共享内存。总线锁是把CPU和内存之间通信锁住了,这使得锁定期间,其他处理器不能操作其他内存地址的数据,所以总线锁锁定的开销比较大。
(2)缓存锁定Cacheline Lock:基本都采用缓存一致性协议(MESI)。
这部分可以参考:
《现代操作系统:原书第4版》:第8章:多处理机系统
说说无锁(Lock-Free)编程那些事:https://zhuanlan.zhihu.com/p/55178896

参考资料

《现代操作系统:原书第4版》
《多核编程入门》
atomic实现原理:https://zhuanlan.zhihu.com/p/115355303
cache之多核一致性(一) - 总线上没有秘密:https://zhuanlan.zhihu.com/p/94811032
原子操作以及加锁机制:https://blog.csdn.net/YL970302/article/details/90079216
说说无锁(Lock-Free)编程那些事:https://zhuanlan.zhihu.com/p/55178896
computer cache:https://www.dazhuanlan.com/2019/12/05/5de8cdae23372/

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值