自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
信号量对互斥来讲是非常有用的工具,但它并不是内核提供的唯一的这类工具。相反,大多数锁定通过称为“自旋锁”的机制实现。和信号量不同,自旋锁可在不能休眠的代码中使用,比如中断处理例程。在正确使用的情况下,自旋锁通常可以提供比信号量更高的性能。
自旋锁原语所需要包含的文件是<linux/spinlock.h>。实际的锁具有spinlock_t类型。和其他任何数据结构类似,一个自旋锁必须被初始化。
编译时初始化:
spinlock_t my_lock = SPIN_LOCK_UNLOCKED;
运行时初始化:
void spin_lock_init(spinlock_t *lock);
获取锁:
void spin_lock(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
void spin_lock_irq(spinlock_t *lock);
void spin_lock_bh(spinlock_t *lock);
spin_lock_irqsave会在获得自旋锁之前禁止中断(只在本地处理器上),而先前的中断状态保存在flags中。
如果我们能确保没有任何其他代码禁止本地处理器的中断(或者换句话说,我们能够确保在释放自旋锁时应该启用中断),则可以使用spin_lock_irq,而无需保存标志。
spin_lock_bh在获得锁之前禁止软件中断,但是会让硬件中断保持打开。这里bn是bottom half的缩写,也就是中断的底半部(软件中断),和它对应的中断的顶半部(硬件中断)。
如果我们有一个自旋锁,它可以被运行在(硬件或软件)中断上下文中的代码获得,则必须使用某个禁止中断的spin_lock形式,因为使用其他的锁定函数迟早会导致系统死锁。如果我们不会在硬件中断处理例程中访问自旋锁,但可能在软件中断访问,则应该使用spin_lock_bh,以便在安全地避免死锁的同时还能服务硬件中断。
释放锁:
void spin_unlock(spinlock_t *lock);
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
void spin_unlock_irq(spinlock_t *lock);
void spin_unlock_bn(spinlock_t *lock);
还有两个非阻塞的版本:
void spin_trylock(spinlock *lock);
void spin_trylock_bh(spinlock *lock);
很重要的一点,任何拥有自旋锁的代码都必须是原子的。它不能休眠,事实上,它不能因为任何原因放弃处理器,除了服务中断以外(某些情况下此时也不能放弃处理器)。
许多操作会使程序进入休眠,例如copy_from_user、kmalloc等