秒懂自旋锁:spin_lock_irq示例
1、spin_lock_irq的作用原理
(1) 禁用当前核的任务调度:例如通过 preempt_disable()禁止当前核的任务抢占。
(2) 关闭当前核的中断:例如通过 local_irq_disable()关闭当前核的中断。
(3) 其他任务、中断如果也要获取同一锁,会进入自旋等待状态,直到成功获取到该锁。
(4) spin_unlock_irq 则会 开当前核的中断、开当前核的任务调度。
2、适用场景
2.1、场景示例
假如在SMP系统下,0核、1核的多个任务、中断都会操作同一个全局变量 global_data,那么可能发生与期望不符的现象。
例如 0核的任务A执行global_data=1后,1核的irq_handler1瞬间执行global_data=6,
那么任务A打印的global_data值就会变成【6】。
不想某段代码被任务抢占、被中断打断,就加spin_lock_irq和spin_unlock_irq 来保护这段临界代码。
int global_data = 0;
0核:
taskA()
{
spin_lock_irq
临界代码A:global_data=1;
临界代码B:printf("global_data=%d\n",global_data);
spin_unlock_irq
}
taskB()
{
spin_lock_irq
临界代码A:global_data=2;
临界代码B:printf("global_data=%d\n",global_data);
spin_unlock_irq
}
irq_handler0()
{
spin_lock_irq
临界代码A:global_data=3;
临界代码B:printf("global_data=%d\n",global_data);
spin_unlock_irq
}
1核:
taskC()
{
spin_lock_irq
临界代码A:global_data=4;
临界代码B:printf("global_data=%d\n",global_data);
spin_unlock_irq
}
taskD()
{
spin_lock_irq
临界代码A:global_data=5;
临界代码B:printf("global_data=%d\n",global_data);
spin_unlock_irq
}
irq_handler1()
{
spin_lock_irq
临界代码A:global_data=6;
临界代码B:printf("global_data=%d\n",global_data);
spin_unlock_irq
}
2.2、效果解析
当0核任务A执行spin_lock_irq进入临界代码区后,会正确地执行临界代码。
(1) 同一核(核0)的任务和中断
任务调度、抢占(包括更高优先级任务抢占):不会发生。spin_lock_irq已经禁用当前核的内核抢占。
中断抢占:不会发生。spin_lock_irq已经关闭当前核的中断。
(2) 其他核(核1)的任务和中断
核1的任务:假如任务会获取该锁,会进入自旋等待。
核1的中断:假如中断会获取该锁,会进入自旋等待。
假如核1的任务、中断不会获取该锁,那么不存在竞争,核1该执行啥任务、中断就执行啥任务、中断。
3、spin_lock
对比spin_lock_irq, spin_lock不会关当前CPU的中断。
4、spin_lock_irqsave
对比spin_lock_irq,spin_lock_irqsave是lock时先保存当前CPU的中断状态并确保关中断,unlock时恢复先前保存的中断状态。

浙公网安备 33010602011771号