原子操作 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);
第一个参数:是个指向内存地址的指针。
第二个参数:是要搜索的总位数。
返回值:是第一个被置位(或未被置位)的位号
内核定义了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);
第一个参数:是个指向内存地址的指针。
第二个参数:是要搜索的总位数。
返回值:是第一个被置位(或未被置位)的位号
相关文章推荐
- (转)没有atomic.h后如何在linux实现原子操作
- 深入理解Atomic原子操作和volatile非原子性
- 原子性操作atomic_t
- C++11 并发指南六(atomic 类型详解四 C 风格原子操作介绍)
- 5.1 CUDA atomic原子操作
- atomic_read原子操作
- 原子操作 atomic_cmpxchg()/Atomic_read()/Atomic_set()/Atomic_add()/Atomic_sub()/atomic_clear_mask()
- 多线程原子操作:AtomicBoolean
- ACE学习(二)原子操作与ACE_Atomic_Op
- Linux 设备驱动--- 并发 与 竞态 --- atomic_t --- atomic_dec_and_test --- 原子操作
- Java多线程之JUC原子类 - 以原子方式操作数组AtomicLongArray
- atomic_inc 原子操作
- 4000 muduo库 AtomicIntergerT原子操作模板类
- atomic 原子操作练习
- C++0x 内存模型和原子操作 (std:::atomic memory order等相关资料)
- Java原子操作AtomicInteger的用法
- 原子操作atomic_t
- 多线程环境下,基本增减赋值操作的原子性实验[atomic,mutex]
- C++0x 内存模型和原子操作 (std:::atomic memory order等相关资料)
- 原子操作 AtomicInteger