原子操作 atomic_t

1. atomic_t 定义及其原因:
内核定义了atomic_t 数据类型,作为对 整数计数器的原子操作的基础。
  1. typedef struct {  
  2.     int counter;  
  3. } atomic_t;  
这里引入了一个特殊的数据类型,而不是直接使用int类型,原因如下:
a. 让原子操作函数只接收 atomic_t 类型的操作数,可以确保原子操作只与这种特殊类型数据一起使用,进而保证了该类型数据不会被传递给其他非原子操作函数。
如果对一个数据,一会采用原子操作,一会又不用原子操作,这没什么好处。
b. 使用 atomic_t 类型确保编译器不对相应的值进行访问优化,这使得原子操作最终接收到正确的内存地址,而不是一个别名。
c. 最后,在不同体系结构上实现原子操作时,使用 atomic_t 可以屏蔽各类体系结构的差异。


原子本意就是不可分割的微粒,所以原子操作就是不可的指令;也就是指在执行过程中不会被别的代码所中断的操作。
各个CPU平台有各自的原子操作实现方式,基本都是通过汇编实现的。

内核提供了两组原子操作接口: 整型原子操作和位原子操作

2. 整型原子操作

整型的原子操作只能对 atomic_t 类型的数据进行处理:

  1. atomic_t v;     //定义 v 原子变量  
void atomic_set(atomic_t *v, int i);   //设置原子变量v的值为i
  1. /** 
  2.  * atomic_set - set atomic variable 
  3.  * @v: pointer of type atomic_t 
  4.  * @i: required value 
  5.  * 
  6.  * Atomically sets the value of @v to @i. 
  7.  */  
  8. #define atomic_set(v, i) (((v)->counter) = (i))  
atomic_t v = ATOMIC_INIT(0);            //定义原子变量v, 并初始化为0
  1. #define ATOMIC_INIT(i)  { (i) }  
atomic_read(atomic_t *v);              //获得原子变量的值,并将 atomic_t 装换位 int 类型的返回值, 应用如下:
  1. printk("%d\n, atomic_read(&v)");   //打印v的值。  
atomic_read()定义:
  1. /** 
  2.  * atomic_read - read atomic variable 
  3.  * @v: pointer of type atomic_t 
  4.  * 
  5.  * Atomically reads the value of @v. 
  6.  */  
  7. #define atomic_read(v)  (*(volatile int *)&(v)->counter)  
  1. void atomic_add(int i, atomic_t *v);    //原子变量+i  
  2. void atomic_sub(int i, atomic_t *v);    //原子变量-i  
原子操作最常见的用途是实现计数器,可以用下面两个函数来实现计数器功能:
  1. void atomic_inc(atomic_t *v);           //原子变量+1  
  2. void atomic_dec(atomic_t *v);           //原子变量-1  
还可以用原子整数操作原子的执行一个操作,并检查结果:
对原子变量执行自增,自减和减操作后(注意没有加),测试其是否为0,为0则返回true,否则返回false

  1. int atomic_inc_and_test(atomic_t *v);  
  2. int atomic_dec_and_test(atomic_t *v);  
  3. int atomic_sub_and_test(int i, atomic_t *v);  
  1. int atomic_add_negative(int i, atomic_t *v); //原子的给 v 加 i, 测试结果是否为负数。如果是负数,返回真;否则返回假。  
对原子变量进行加/减,自增/自减操作,并返回新的值。
  1. int atomic_add_return(int i, atomic_t *v);  
  2. int atomic_sub_return(int i, atomic_t *v);  
  3. int atomic_inc_return(atomic_t *v);  
  4. int atomic_sub_return(atomic_t *v);  
原子操作通常是内联函数(inline),往往是通过内嵌汇编指令来实现的。

64位整型原子操作:

对于64位的原子操作,使用 atomic64_t 类型,其功能和32位一模一样,使用方法也完全相同,就是把 atomic 变成了 atomic64。

与 atomic_t 一样, atomic64_t 类型其实就是一个多长整型的封装类:

  1. typedef struct {  
  2.     long long counter;  
  3. } atomic64_t;  

3. 位原子操作

位操作函数是对普通的内存地址进行操作的。

它的参数是一个指针和一个位号,第0位是给定地址的最低有效位;32位机上,31位是地址最高有效位;而第32位是下一个字的最低有效位

虽然原子位操作在大多数情况下,是对一个字长的内存进行访问的,因而位号位于0-31(64位机是0-63),但是对位号的范围并没有限制。

  1. void set_bit(nr, void *addr);    //将addr地址的nr位 置为1  
  2.   
  3. void clear_bit(nr, void *addr);  //将addr地址的nr位 清0  
  4.   
  5. void change_bit(nr, void *addr);  //对addr地址的nr位 反置  
  6.   
  7. int test_bit(nr, void *addr);    //返回addr地址的nr位  
下面函数是:先原子的设置/清空/翻转 addr 所指地址的第nr位,然后返回原先的值。
  1. int test_and_set_bit(nr, void *addr);  
  2. int test_and_clear_bit(nr, void *addr);  
  3. int test_and_change_bit(nr, void *addr);  

内核还提供两个函数,用来从指定地址开始搜索第一个被置位(或未被置位)的位号:

  1. int find_fist_bit(unsigned long *addr, unsigned int size);  
  2.   
  3. int find_first_zero_bit(unsigned long *addr, unsigned int size);  

第一个参数:是个指向内存地址的指针。

第二个参数:是要搜索的总位数。

返回值:是第一个被置位(或未被置位)的位号



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值