互斥技术-原子变量
原子变量
普通变量count++:
看起来是一句话:实际是三个步骤:第一:首先要把这个变量在内存当中取到CPU:第二:把这个变量进行++;第三:把这个变量的值送回内存:所以这是分了三个步骤:每一个步骤都有可能被打断,所以对这个值的操作不原子.
原子:即一气呵成:
一旦成功,则所有过程都成功,一旦失败,所有过程都失败.所以原子变量并不是不可被打断的.
原子变量count++:
也是分成三个步骤:前两个步骤与普通变量一样:第三个步骤:在进行往内存写的时候,会检测是否在我取出之后这个变量被重新写入过,如果被写入过,则重新把这个变量读取出来进行++,然后在写入.(这个功能实现的方式是在下面这个atomic.h中的一段内嵌汇编实现的)
原子变量API
是基于架构实现的,所有API都是在对应架构下的atomic.h文件中,如arch/arm/include/asm/atomic.h,这里就不贴出来了。
代码分析
结构体
typedef struct {
int counter;
} atomic_t;
初始化一个原子变量
atomic_t v = ATOMIC_INIT(0);
#define atomic_inc_return(v) atomic_add_return(1, (v))
static inline int atomic_add_return(int i, atomic_t *v)
{
unsigned long tmp;
int result;
smp_mb();
__asm__ __volatile__("@ atomic_add_return\n"
"1: ldrex %0, [%3]\n" /*【1】独占方式加载v->counter到result*/
" add %0, %0, %4\n" /*【2】result加一*/
" strex %1, %0, [%3]\n" /*【3】独占方式将result值写回v->counter*/
" teq %1, #0\n" /*【4】判断strex更新内存是否成*/
" bne 1b" /*【5】不成功跳转到1:*/
: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) /*输出部*/
: "r" (&v->counter), "Ir" (i) /*输入部*/
: "cc"); /*损坏部*/
smp_mb();
return result;
}
1)LDREXB和STREXB:对内存中的一个字节(Byte,8 bit)进行独占访问;
2)LDREXH和STREXH:中的一个半字(Half Word,16 bit)进行独占访问;
3)LDREXD和STREXD:中的一个双字(Double Word,64 bit)进行独占访问。
插曲:中断除了正在运行的指令不可以打断,其他任何过程都可以打断:在不可抢占的内核的一段代码:在之前屏蔽中断,操作之后再打开中断,这样中间的一段代码是不可能被其他任何情况打断了.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)