原子操作 atomic_t

本文介绍了Linux系统中整型原子操作,重点讲解了atomic_t和atomic64_t类型,用于处理32位和64位整型数据。内容包括位操作函数的工作原理,如如何对指定地址进行位操作,并提供了搜索置位或未置位位号的函数。
1. atomic_t 定义及其原因:
内核定义了atomic_t 数据类型,作为对整数计数器的原子操作的基础。
typedef struct {
	int counter;
} atomic_t;
这里引入了一个特殊的数据类型,而不是直接使用int类型,原因如下:
a. 让原子操作函数只接收 atomic_t 类型的操作数,可以确保原子操作只与这种特殊类型数据一起使用,进而保证了该类型数据不会被传递给其他非原子操作函数。
如果对一个数据,一会采用原子操作,一会又不用原子操作,这没什么好处。
b. 使用 atomic_t 类型确保编译器不对相应的值进行访问优化,这使得原子操作最终接收到正确的内存地址,而不是一个别名。
c. 最后,在不同体系结构上实现原子操作时,使用 atomic_t 可以屏蔽各类体系结构的差异。


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

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

2. 整型原子操作

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

atomic_t v;     //定义 v 原子变量
void atomic_set(atomic_t *v, int i);   //设置原子变量v的值为i

/**
 * atomic_set - set atomic variable
 * @v: pointer of type atomic_t
 * @i: required value
 *
 * Atomically sets the value of @v to @i.
 */
#define atomic_set(v, i) (((v)->counter) = (i))
atomic_t v = ATOMIC_INIT(0);            //定义原子变量v, 并初始化为0

#define ATOMIC_INIT(i)	{ (i) }
atomic_read(atomic_t *v);              //获得原子变量的值,并将 atomic_t 装换位 int 类型的返回值, 应用如下:

printk("%d\n, atomic_read(&v)");   //打印v的值。
atomic_read()定义:

/**
 * atomic_read - read atomic variable
 * @v: pointer of type atomic_t
 *
 * Atomically reads the value of @v.
 */
#define atomic_read(v)	(*(volatile int *)&(v)->counter)

void atomic_add(int i, atomic_t *v);    //原子变量+i
void atomic_sub(int i, atomic_t *v);    //原子变量-i
原子操作最常见的用途是实现计数器,可以用下面两个函数来实现计数器功能:
void atomic_inc(atomic_t *v);           //原子变量+1
void atomic_dec(atomic_t *v);           //原子变量-1
还可以用原子整数操作原子的执行一个操作,并检查结果:
对原子变量执行自增,自减和减操作后(注意没有加),测试其是否为0,为0则返回true,否则返回false

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

64位整型原子操作:

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

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

typedef struct {
	long long counter;
} atomic64_t;

3. 位原子操作

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

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

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

void set_bit(nr, void *addr);    //将addr地址的nr位 置为1

void clear_bit(nr, void *addr);  //将addr地址的nr位 清0

void change_bit(nr, void *addr);  //对addr地址的nr位 反置

int test_bit(nr, void *addr);    //返回addr地址的nr位
下面函数是:先原子的设置/清空/翻转 addr 所指地址的第nr位,然后返回原先的值。
int test_and_set_bit(nr, void *addr);
int test_and_clear_bit(nr, void *addr);
int test_and_change_bit(nr, void *addr);

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

int find_fist_bit(unsigned long *addr, unsigned int size);

int find_first_zero_bit(unsigned long *addr, unsigned int size);

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

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

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





评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值