Linux内核:访问per-CPU变量时为何禁用抢占?
关于
get_cpu_var()宏禁用抢占的原因及内核抢占的说明 首先咱们先拆解下你提到的这个宏:
#define get_cpu_var(var) \ (*({ \ preempt_disable(); \ this_cpu_ptr(&var); \ }))
它的核心作用是安全获取当前CPU对应的per-CPU变量实例,接下来逐个解答你的问题:
1. 为什么要在此处禁用抢占?
per-CPU变量的本质是每个CPU拥有独立的变量副本,目的是减少锁竞争、提升性能。但这里有个关键前提:你拿到的指针绑定的是当前CPU的副本。
如果不禁用抢占,会出现致命问题:假设进程A在CPU0上调用get_cpu_var()拿到了CPU0上的var副本指针,紧接着还没完成对这个变量的操作,就被调度器抢占,切换到了CPU1上运行。这时候进程A如果继续使用之前拿到的指针,访问的还是CPU0的副本,而不是当前所在CPU1的副本——这完全违背了per-CPU变量的设计初衷,会导致数据错误或者不一致。
所以preempt_disable()的作用是锁住当前CPU绑定关系:从获取per-CPU变量指针开始,直到你调用put_cpu_var()(对应解锁抢占)这段时间,当前进程不会被调度到其他CPU,确保你访问的始终是当前CPU的正确副本。
2. 内核环境中难道不会发生抢占吗?
当然会!现代Linux内核默认支持抢占式内核(通过CONFIG_PREEMPT系列配置开启),内核空间的代码并非完全不可抢占:
- 在进程上下文(比如系统调用执行过程、内核线程运行时),只要当前代码没有持有自旋锁、没有处于中断上下文,调度器就可以抢占当前进程,让更高优先级的进程运行。
- 只有在一些特殊场景下内核才不会被抢占:比如持有自旋锁时、中断上下文执行时、调用了
preempt_disable()的代码段内。
简单说,内核本身是执行抢占操作的主体,但这并不意味着内核代码永远不会被抢占——恰恰相反,抢占式内核的设计就是为了提升系统响应性,让高优先级任务能更快得到执行。
内容的提问来源于stack exchange,提问作者tomer.z
相关产品推荐
相关产品推荐

