您的位置:首页 > 其它

原子操作 atomic_t

2014-05-09 17:25 519 查看
1. atomic_t 定义及其原因:

内核定义了atomic_t 数据类型,作为对整数计数器的原子操作的基础。

[cpp]
view plaincopy

typedef struct {
int counter;
} atomic_t;

这里引入了一个特殊的数据类型,而不是直接使用int类型,原因如下:

a. 让原子操作函数只接收 atomic_t 类型的操作数,可以确保原子操作只与这种特殊类型数据一起使用,进而保证了该类型数据不会被传递给其他非原子操作函数。

如果对一个数据,一会采用原子操作,一会又不用原子操作,这没什么好处。

b. 使用 atomic_t 类型确保编译器不对相应的值进行访问优化,这使得原子操作最终接收到正确的内存地址,而不是一个别名。

c. 最后,在不同体系结构上实现原子操作时,使用 atomic_t 可以屏蔽各类体系结构的差异。

原子本意就是不可分割的微粒,所以原子操作就是不可的指令;也就是指在执行过程中不会被别的代码所中断的操作。

各个CPU平台有各自的原子操作实现方式,基本都是通过汇编实现的。



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


2. 整型原子操作

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

[cpp]
view plaincopy

atomic_t v; //定义 v 原子变量

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

[cpp]
view plaincopy

/**
* 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

[cpp]
view plaincopy

#define ATOMIC_INIT(i) { (i) }

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

[cpp]
view plaincopy

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

atomic_read()定义:

[cpp]
view plaincopy

/**
* 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)

[cpp]
view plaincopy

void atomic_add(int i, atomic_t *v); //原子变量+i
void atomic_sub(int i, atomic_t *v); //原子变量-i

原子操作最常见的用途是实现计数器,可以用下面两个函数来实现计数器功能:

[cpp]
view plaincopy

void atomic_inc(atomic_t *v); //原子变量+1
void atomic_dec(atomic_t *v); //原子变量-1

还可以用原子整数操作原子的执行一个操作,并检查结果:

对原子变量执行自增,自减和减操作后(注意没有加),测试其是否为0,为0则返回true,否则返回false


[cpp]
view plaincopy

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);

[cpp]
view plaincopy

int atomic_add_negative(int i, atomic_t *v); //原子的给 v 加 i, 测试结果是否为负数。如果是负数,返回真;否则返回假。

对原子变量进行加/减,自增/自减操作,并返回新的值。

[cpp]
view plaincopy

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 类型其实就是一个多长整型的封装类:

[cpp]
view plaincopy

typedef struct {
long long counter;
} atomic64_t;

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

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

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

[cpp]
view plaincopy

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位,然后返回原先的值。

[cpp]
view plaincopy

int test_and_set_bit(nr, void *addr);
int test_and_clear_bit(nr, void *addr);
int test_and_change_bit(nr, void *addr);

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

[cpp]
view plaincopy

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

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

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

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

返回值:是第一个被置位(或未被置位)的位号
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: