假设这样一种情况:有多个线程(或多核)需要在共享数据A满足某一条件时,对A进行操作.
以下举例两种实现
Fun_1()
{ lock()--------------1.1
Result=Check(A)-----1.2
Unlock()------------1.3
-------------RISK!!!!
Lock()--------------1.4
Operate(A,result)---1.5
Unlock()------------1.6
}
Fun_2()
{ lock()--------------2.1
Result=Check(A)-----2.2
Operate(A,result)---2.3
Unlock()------------2.4
}
以上函数,只有fun_2 是安全的,FUN_1存在风险:
单核下:
当前线程完1.3 后如果发生了线程调度,那么数据a可能被其它线程修改。
重新回到1.4时,RESULT 已经不对了!!!
多核下:
当前线程完1.3 后如果发生了线程调度,那么数据a可能被其它线程修改。
重新回到1.4时,RESULT 已经不对了!!!
当前线程完1.3 后如果第二个核正好在运行代码1.5,那么数据a会被修改。
重新回到1.4时,RESULT 已经不对了!!!
***********************************************************************************************
锁的选择分为“信号量”“和自旋转锁”:
信号量会使程序休眠
自旋锁会关抢占,并进行忙等待
一般如果访问时间较短,或者使用多核处理器可以选择自旋锁
如果访问的时间较长(大于系统进行两次调度需要的时间)且是单核处理器,则可以选择信号量。
************************************************************************************************
linux下自旋锁函数:
spin_lock 使用情况:如果被保护的共享资源“只在进程上下文访问”
功能: 最基本的锁,没有对中断处理
spin_lock_bh 适用情况:如果被保护的共享资源“只在进程上下文和tasklet或timer上下文访问”
功能: spin_lock为基础,释放时开启上锁时禁止的软中断
spin_lock_irq 适用情况:如果被保护的共享资源“只在进程上下文和tasklet或timer上下文访问”
功能: spin_lock为基础,释放时开启中断
spin_lock_irqsave 适用情况:效率最差的一种,但当你不知道用哪个好时,可以用它
功能: spin_lock为基础,释放时恢复上锁时的中断状态
*******************************************************************************************************************
以下说明摘自网上:
如果被保护的共享资源“只在进程上下文访问和软中断上下文访问”,那么当在进程上下文访问共享资源时,可能被软中断打断,从而可能进入软中断上下文来对被保护的共享资源访问,因此对于这种情况,对共享资源的访问必须使用spin_lock_bh和spin_unlock_bh来保护。