什么是自旋锁
是指临界区资源被持有锁线程A拥有的时候,别的线程B只能原地等待不会进入睡眠,直到A释放锁,那么A才可以访问临界区资源
注意:自旋锁一般是用在等待时间比较短的地方,如果等待时间较长的话一般考虑使用信号量
结构体:spinlock_t
相关API函数
下面的API是不考虑中断情况下的
主要是下面两个函数
获得锁函数 void spin_lock(spinlock_t *lock) 获取指定的自旋锁,也叫做加锁
解锁函数 void spin_unlock(spinlock_t *lock) 释放指定的自旋锁
注意:上面的自旋锁API函数适用于SMP或支持抢占的单CPU下线程之间的并发访问, 也就是用于线程与线程之间(不考虑中断),被自旋锁保护的临界区一定不能调用任何能够引起睡眠和阻塞的 API 函数,否则的话会可能会导致死锁现象的发生
注意发生死锁:
由于获得锁之后内核会自动禁止抢占,如果线程A进入睡眠的话就相当于放弃了CPU,那么此时B线程就会运行,此时B也想获得锁,但是线程A并没有释放掉锁,并且A由于禁止抢占式不能被唤醒,所以B只能在外面等待,所以就出现死锁
考虑中断的情况
如果线程之间来了个中断,又会是什么情况呢
线程 A 先运行,并且获取到了 lock 这个锁,当线程 A 运行程序的时候中断发生了,中断抢走了CPU 使用权。右边的中断服务函数也要获取 lock 这个锁, 但是这个锁被线程 A 占有着,中断就会一直自旋,等待锁有效。但是在中断服务函数执行完之前,线程 A 是不可能执行的,线程 A 说“你先放手”,中断说“你先放手”,场面就这么僵持着,死锁发生!
最好的解决方法就是获取锁之前关闭本地中断
即调用下面的函数获得锁即可
使用自旋锁一般步骤
注意事项:
总结:
1)自旋锁的使用可以在中断中,如果有中断的话必须使用考虑中断的API获得锁,不然会出现死锁,
2)自旋锁必须是等待时间比较短,因为自旋锁会一直占用CPU,如果需要等待长时间即进入睡眠的话那就考虑信号量,下面一篇介绍信号量
3)自旋锁不能使用睡眠或阻塞的相关函数