Linux内核之内核同步(二)——原子操作

原子操作

原子操作可以保证指令以原子的方式被执行,执行过程不会被打断。Linux内核提供了一个专门的atomic_t类型(一个原子访问计数器),其定义如下:

typedef struct{
	int counter;
}atomic_t;

atomic_t类型定义在/include/linux/types.h中, 这样定义的原因是可以让GCC在编译的时候加以更加严格的类型检查,防止原子类型变量被误操作。随着64位体系结构的普及,64位原子操作被定义为atomic64_t。

typedef struct{
	long counter;
}atomic64_t;

对于atomic_t类型的变量,linux内核提供了一些专门的函数和宏来进行原子操作,如下表:

原子整数操作说明
ATOMIC_INIT(int i)声明atomic_t变量,并初始化为i
atomic_read(v)原子操作读取整数变量v,返回*v
atomic_set(v,i)原子操作把*v置成i
atomic_add(i,v)原子操作*v加i
atomic_add_return(i,v)原子操作v加i,返回v
atomic_add_negative(i,v)原子操作*v加i,为负返1,否则返0
atomic_sub(i,v)原子操作*v减i
atomic_sub_return(i,v)原子操作v减i,返回v
atomic_sub_and_test(i,v)原子操作*v减i,为0返1,否则返0
atomic_inc(v)原子操作*v自加1
atomic_inc_and_test(v)原子操作*v自加1,为0返1,为1返0
atomic_dec(v)原子操作*v自减1
atomic_dec_and_test(v)原子操作*v自减1,为0返1,为1返0

原子操作用法举例

\\定义原子变量
atomic_t u;//定义原子变量u
atomic_t v= ATIMIC_INIT(0);//定义原子变量v,并初始化为0
\\操作原子变量
atomic_set(&v,10);\\原子操作v=10
atomic_add(5,&v);\\原子操作v=v+5=15
atomic_dec(2,&v);\\原子操作v=v-2=13
atomic_sub_and_text(13,&v);\\原子操作v=v-13=0,并返回1
printk("v=%d\n",atomic_read(&v));\\会打印出v的值,即打印v=0

在内核实现计数器时,用锁机制来保护显得有些笨拙,而轻量级地保护内核计数器就可以使用原子操作。
Linux内核除了原子整数操作外,也提供了一组针对位原子操作的函数,如下表所示,它被定义在/include/asm-generic/bitops/atomic.h中,它常被应用于内存管理、设备驱动。

原子位操作说明
set_bit(nr,addr)原子操作设置地址为addr的第nr位
clear_bit(nr,addr)原子操作清除地址为addr的第nr位
change_bit(nr,addr)原子操作,取反地址为addr的第nr位
test_and_set_bit(nr,addr)原子操作设置地址为addr的第nr位,并返回原先的值
test_and_clean_bit(nr,addr)原子操作清除地址为addr的第nr位,并返回原先的值
test_and_clean_bit(nr,addr)原子操作取反地址为addr的第nr位,并返回原先的值
test_bit(nr,addr)原子操作,返回地址为addr的第nr位
find_first_zero_bit(addr,size)addr为内存的起始地址,size为要查找的最大长度,返回第一个为0的位号
find_next_zero_bit(addr,size,offset)addr为内存的起始地址,size为要查找的最大长度,offset
为开始搜索的起始位号,返回第一个为0的位号

注:

  • clear_bit(nr,addr)是原子操作,但不具备加锁功能,若要用于加锁目的,应当调用smp_mb__before_clear_bit 或smp_mb__after_clear_bit函数,以确保任何改变在其他的处理器上是可见的。
  • test_bit(nr,addr)定义如下
#define test_bit(nr, addr)			\
	(__builtin_constant_p((nr))		\
	? constant_test_bit((nr), (addr))	\
	: variable_test_bit((nr), (addr)))

根据nr是否为编译时常数来调用不同的函数

  • 若编译时为常数,则调用constant_test_bit
static __always_inline int constant_test_bit(unsigned int nr, const volatile unsigned long *addr) 
  • 若编译时为非常数,则调用variable_test_bit
static inline int variable_test_bit(int nr, volatile const unsigned long *addr)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值