linux 原子整数操作详解.docx
- 文档编号:26375315
- 上传时间:2023-06-18
- 格式:DOCX
- 页数:9
- 大小:17.40KB
linux 原子整数操作详解.docx
《linux 原子整数操作详解.docx》由会员分享,可在线阅读,更多相关《linux 原子整数操作详解.docx(9页珍藏版)》请在冰豆网上搜索。
linux原子整数操作详解
原子操作,顾名思义,就是说像原子一样不可再细分不可被中途打断。
一个操作是原子操作,意思就是说这个操作是以原子的方式被执行,要一口气执行完,执行过程不能够被OS的其他行为打断,是一个整体的过程,在其执行过程中,OS的其它行为是插不进来的。
在linux中提供了两种形式的原子操作:
一种是对整数进行的操作
一种是对单独的位进行操作
在linux中有一个专门的atomic_t类型(一个24位原子访问计数器)和一些对atomic类型变量进行相应操作的的函数
其atomic_t原型如下:
typedefstruct{volatileintcounter;}atomic_t;
它是一个只含有一个volatile类型的成员变量的结构体;因此编译器不对相应的值进行访问优化(因为是volatile类型的)。
原子整数操作的使用:
常见的用途是计数器,因为计数器是一个很简单的操作,所以无需复杂的锁机制;
能使用原子操作的地方,尽量不使用复杂的锁机制;
对atomic_t类型的变量的使用方法以及对其所能进行的操作:
下面是相应的函数及其原型:
小提示:
******
在其函数的实现体中,有一个LOCK_PREFIX宏定义,如果选了CONFIG_SMP,就会定义这么一个宏,与SMP相关的一些设置,否则LOCK_PREFIX的定义就为空;
******
//原子的读取atomic_t变量的值,v是这个变量的地址
#defineatomic_read(v) ((v)->counter)
//原子的设置atomic_t变量的值,v是这个变量的地址,i要设置的新值;
#defineatomic_set(v,i) (((v)->counter)=(i))
//原子的增加atomic_t变量的值,i是要增加的数值,v是这个变量的地址
static__inline__voidatomic_add(inti,atomic_t*v)
{
__asm____volatile__(
LOCK_PREFIX"addl%1,%0"
:
"=m"(v->counter)
:
"ir"(i),"m"(v->counter));
}
//原子的减少atomic_t变量的值,i是要减少的数值,v是这个变量的地址;
static__inline__voidatomic_sub(inti,atomic_t*v)
{
__asm____volatile__(
LOCK_PREFIX"subl%1,%0"
:
"=m"(v->counter)
:
"ir"(i),"m"(v->counter));
}
//原子的对atomic_t变量的值进行减少i的操作,并且检测其结果是否为0;若为0,返回true,否则,返回false;
//i是要减少的数值,v是这个变量的地址;
static__inline__intatomic_sub_and_test(inti,atomic_t*v)
{
unsignedcharc;
__asm____volatile__(
LOCK_PREFIX"subl%2,%0;sete%1"
:
"=m"(v->counter),"=qm"(c)
:
"ir"(i),"m"(v->counter):
"memory");
returnc;
}
//原子的对atomic_t变量的值进行加1的操作,v是这个变量的地址;
static__inline__voidatomic_inc(atomic_t*v)
{
__asm____volatile__(
LOCK_PREFIX"incl%0"
:
"=m"(v->counter)
:
"m"(v->counter));
}
//原子的对atomic_t变量的值进行减1的操作,v是这个变量的地址;
static__inline__voidatomic_dec(atomic_t*v)
{
__asm____volatile__(
LOCK_PREFIX"decl%0"
:
"=m"(v->counter)
:
"m"(v->counter));
}
//原子的对atomic_t变量的值进行减少1的操作,并且检测其结果是否为0;若为0,返回true,否则,返回false;
//v是这个变量的地址;
static__inline__intatomic_dec_and_test(atomic_t*v)
{
unsignedcharc;
__asm____volatile__(
LOCK_PREFIX"decl%0;sete%1"
:
"=m"(v->counter),"=qm"(c)
:
"m"(v->counter):
"memory");
returnc!
=0;
}
//原子的对atomic_t变量的值进行加1的操作,并且检测其结果是否为0;若为0,返回true,否则,返回false;
//v是这个变量的地址;
static__inline__intatomic_inc_and_test(atomic_t*v)
{
unsignedcharc;
__asm____volatile__(
LOCK_PREFIX"incl%0;sete%1"
:
"=m"(v->counter),"=qm"(c)
:
"m"(v->counter):
"memory");
returnc!
=0;
}
//原子的对atomic_t变量的值进行加i的操作,并且检测其结果是否为负;若为负,返回true,否则,返回false;
//i是要增加的数值,v是这个变量的地址;
static__inline__intatomic_add_negative(inti,atomic_t*v)
{
unsignedcharc;
__asm____volatile__(
LOCK_PREFIX"addl%2,%0;sets%1"
:
"=m"(v->counter),"=qm"(c)
:
"ir"(i),"m"(v->counter):
"memory");
returnc;
}
//原子的对atomic_t变量的值进行加i的操作,并且将所得结果返回;
//i是要增加的数值,v是这个变量的地址;
static__inline__intatomic_add_return(inti,atomic_t*v)
{
int__i;
#ifdefCONFIG_M386
unsignedlongflags;
if(unlikely(boot_cpu_data.x86==3))
gotono_xadd;
#endif
/*Modern486+processor*/
__i=i;
__asm____volatile__(
LOCK_PREFIX"xaddl%0,%1;"
:
"=r"(i)
:
"m"(v->counter),"0"(i));
returni+__i;
#ifdefCONFIG_M386
no_xadd:
/*Legacy386processor*/
local_irq_save(flags);
__i=atomic_read(v);
atomic_set(v,i+__i);
local_irq_restore(flags);
returni+__i;
#endif
}
//原子的对atomic_t变量的值进行减i的操作,并且将所得结果返回;
//i是要减少的数值,v是这个变量的地址;
static__inline__intatomic_sub_return(inti,atomic_t*v)
{
returnatomic_add_return(-i,v);
}
//原子的比较old与v是否相等,若相等,则把new的值写入到v中,并且返回old的值;
#defineatomic_cmpxchg(v,old,new)((int)cmpxchg(&((v)->counter),old,new))
//原子的比较
#defineatomic_xchg(v,new)(xchg(&((v)->counter),new))
/**
*atomic_add_unless-addunlessthenumberisagivenvalue
*@v:
pointeroftypeatomic_t
*@a:
theamounttoaddtov...
*@u:
...unlessvisequaltou.
*
*Atomicallyadds@ato@v,solongasitwasnot@u.
*Returnsnon-zeroif@vwasnot@u,andzerootherwise.
*/
//原子的对atomic_t变量的值进行加a的操作,直到v等于u,如果v与u不等,返回非零值;否则返回0;
//a是要增加的数值,v是这个变量的地址,u是要比较的值;
#defineatomic_add_unless(v,a,u) \
({ \
intc,old; \
c=atomic_read(v); \
for(;;){ \
if(unlikely(c==(u))) \
break; \
old=atomic_cmpxchg((v),c,c+(a)); \
if(likely(old==c)) \
break; \
c=old; \
} \
c!
=(u); \
})
#defineatomic_inc_not_zero(v)atomic_add_unless((v),1,0)
#defineatomic_inc_return(v) (atomic_add_return(1,v))
#defineatomic_dec_return(v) (atomic_sub_return(1,v))
//掩码
/*Thesearex86-specific,usedbysomeheaderfiles*/
#defineatomic_clear_mask(mask,addr)\
__asm____volatile__(LOCK_PREFIX"andl%0,%1"\
:
:
"r"(~(mask)),"m"(*addr):
"memory")
#defineatomic_set_mask(mask,addr)\
__asm____volatile__(LOCK_PREFIX"orl%0,%1"\
:
:
"r"(mask),"m"(*(addr)):
"memory")
下面举例说明原子操作的用法:
定义一个atomic_c类型的数据很简单,还可以定义时给它设定初值:
(1)atomic_tu; /*定义u*/
(2)atomic_tv=ATOMIC_INIT(0) /*定义v并把它初始化为0*/
对其操作:
(1)atomic_set(&v,4) /*v=4(原子地)*/
(2)atomic_add(2,&v) /*v=v+2=6(原子地)*/
(3)atomic_inc(&v) /*v=v+1=7(原子地)*/
如果需要将atomic_t转换成int型,可以使用atomic_read()来完成:
printk(“%d\n”,atomic_read(&v)); /*会打印7*/
原子整数操作最常见的用途就是实现计数器。
使用复杂的锁机制来保护一个单纯的计数器是很笨拙的,所以,开发者最好使用atomic_inc()和atomic_dec()这两个相对来说轻便一点的操作。
还可以用原子整数操作原子地执行一个操作并检查结果。
一个常见的例子是原子的减操作和检查。
intatomic_dec_and_test(atomic_t*v)
这个函数让给定的原子变量减1,如果结果为0,就返回1;否则返回0
原子位操作
操作函数的参数是一个指针和一个位号
第0位是给定地址的最低有效位
原子位操作中没有特殊的数据类型
例如:
set_bit(0,&word);
如:
标志寄存器EFLSGS的系统标志,用于控制I/O访问,可屏蔽硬件中断。
共32位,不同的位代表不同的信息,对其中信息改变都是通过位操作实现的
原子操作中的位操作部分函数如下:
voidset_bit(intnr,void*addr) 原子设置addr所指的第nr位
voidclear_bit(intnr,void*addr) 原子的清空所指对象的第nr位
voidchange_bit(nr,void*addr) 原子的翻转addr所指的第nr位
inttest_bit(nr,void*addr) 原子的返回addr位所指对象nr位
inttest_and_set_bit(nr,void*addr) 原子设置addr所指对象的第nr位,并返回原先的值
inttest_and_clear_bit(nr,void*addr) 原子清空addr所指对象的第nr位,并返回原先的值
inttest_and_change_bit(nr,void*addr) 原子翻转addr所指对象的第nr位,并返回原先的值
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux 原子整数操作详解 原子 整数 操作 详解