1. atomic_t 定义及其原因:
这里引入了一个特殊的数据类型,而不是直接使用int类型,原因如下:
a. 让原子操作函数只接收 atomic_t 类型的操作数,可以确保原子操作只与这种特殊类型数据一起使用,进而保证了该类型数据不会被传递给其他非原子操作函数。
如果对一个数据,一会采用原子操作,一会又不用原子操作,这没什么好处。
b. 使用 atomic_t 类型确保编译器不对相应的值进行访问优化,这使得原子操作最终接收到正确的内存地址,而不是一个别名。
c. 最后,在不同体系结构上实现原子操作时,使用 atomic_t 可以屏蔽各类体系结构的差异。
原子本意就是不可分割的微粒,所以原子操作就是不可的指令;也就是指在执行过程中不会被别的代码所中断的操作。
void atomic_set(atomic_t *v, int i); //设置原子变量v的值为i
atomic_t v = ATOMIC_INIT(0); //定义原子变量v, 并初始化为0
atomic_read(atomic_t *v); //获得原子变量的值,并将 atomic_t 装换位 int 类型的返回值, 应用如下:
atomic_read()定义:
原子操作最常见的用途是实现计数器,可以用下面两个函数来实现计数器功能:
还可以用原子整数操作原子的执行一个操作,并检查结果:
对原子变量执行自增,自减和减操作后(注意没有加),测试其是否为0,为0则返回true,否则返回false
对原子变量进行加/减,自增/自减操作,并返回新的值。
原子操作通常是内联函数(inline),往往是通过内嵌汇编指令来实现的。
3. 位原子操作
下面函数是:先原子的设置/清空/翻转 addr 所指地址的第nr位,然后返回原先的值。
内核定义了atomic_t 数据类型,作为对
整数计数器的原子操作的基础。
- typedef struct {
- int counter;
- } atomic_t;
a. 让原子操作函数只接收 atomic_t 类型的操作数,可以确保原子操作只与这种特殊类型数据一起使用,进而保证了该类型数据不会被传递给其他非原子操作函数。
如果对一个数据,一会采用原子操作,一会又不用原子操作,这没什么好处。
b. 使用 atomic_t 类型确保编译器不对相应的值进行访问优化,这使得原子操作最终接收到正确的内存地址,而不是一个别名。
c. 最后,在不同体系结构上实现原子操作时,使用 atomic_t 可以屏蔽各类体系结构的差异。
原子本意就是不可分割的微粒,所以原子操作就是不可的指令;也就是指在执行过程中不会被别的代码所中断的操作。
各个CPU平台有各自的原子操作实现方式,基本都是通过汇编实现的。
内核提供了两组原子操作接口: 整型原子操作和位原子操作
内核提供了两组原子操作接口: 整型原子操作和位原子操作
2. 整型原子操作
整型的原子操作只能对 atomic_t 类型的数据进行处理:
- atomic_t v; //定义 v 原子变量
- /**
- * 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))
- #define ATOMIC_INIT(i) { (i) }
- printk("%d\n, atomic_read(&v)"); //打印v的值。
- /**
- * 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);
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位
- 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);
第一个参数:是个指向内存地址的指针。
第二个参数:是要搜索的总位数。
返回值:是第一个被置位(或未被置位)的位号