linux内核机制:Linux系统内核的同步机制-自旋锁



自旋锁最多只能被个可执行线程持有自旋锁不会引起者睡眠如果个执行线程试图获得个已经被持有自旋锁那么线程就会直进行忙循环直等待下去在那里看是否该自旋锁保持者已经释放了锁"自旋"词就是因此而得名 由于自旋锁使用者般保持锁时间非常短因此选择自旋而不是睡眠是非常必要自旋锁效率远高于互斥锁 信号量和读写信号量适合于保持时间较长情况它们会导致者睡眠因此只能在进程上下文使用(_trylock变种能够在中断上下文使用);而自旋锁适合于保持时间非常短情况个被争用自旋锁使得请求它线程在等待重新可用时自旋特别浪费处理时间这是自旋锁要害的处所以自旋锁不应该被长时间持有在实际应用中自旋锁代码只有几行而持有自旋锁时间也般不会超过两次上下方切换因线程旦要进行切换就至少花费切出切入两次自旋锁占用时间如果远远长于两次上下文切换我们就可以让线程睡眠这就失去了设计自旋锁意义 如果被保护共享资源只在进程上下文访问使用信号量保护该共享资源非常合适如果对共享资源访问时间非常短自旋锁也可以但是如果被保护共享资源需要在中断上下文访问(包括底半部即中断处理句柄和顶半部即软中断)就必须使用自旋锁 自旋锁保持期间是抢占失效而信号量和读写信号量保持期间是可以被抢占自旋锁只有在内核可抢占或SMP情况下才真正需要在单CPU且不可抢占内核下自旋锁所有操作都是空操作 个执行单元要想访问被自旋锁保护共享资源必须先得到锁在访问完共享资源后必须释放锁如果在获取自旋锁时没有任何执行单元保持该锁那么将立即得到锁;如果在获取自旋锁时锁已经有保持者那么获取锁操作将自旋在那里直到该自旋锁保持者释放了锁 无论是互斥锁还是自旋锁在任何时刻最多只能有个保持者也就说在任何时刻最多只能有个执行单元获得锁自旋锁实现和体系结构密切相关代码般通过汇编实现定义在文件,实际用到接口定义在文件夹 中, 自旋锁API有:
CODE:spin_lock_init(x)



该宏用于化自旋锁x自旋锁在真正使用前必须先该宏用于动态化指定
CODE:DEFINE_SPINLOCK(x)



该宏声明个自旋锁x并化它该宏在2.6.11中第次被定义在先前内核中并没有该宏
CODE:SPIN_LOCK_UNLOCKED



该宏用于静态个自旋锁
CODE:DEFINE_SPINLOCK(x)等同于spinlock_t x = SPIN_LOCK_UNLOCKEDspin_is_locked(x) )



该宏用于判断自旋锁x是否已经被某执行单元保持(即被锁)如果是返回真否则返回假
CODE:spin_unlock_wait(x)



该宏用于等待自旋锁x变得没有被任何执行单元保持如果没有任何执行单元保持该自旋锁该宏立即返回否则将循环在那里直到该自旋锁被保持者释放
CODE:spin_trylock(lock)



该宏尽力获得自旋锁lock如果能立即获得锁它获得锁并返回真否则不能立即获得锁立即返回假它不会自旋等待lock被释放
CODE:spin_lock(lock)



该宏用于获得自旋锁lock如果能够立即获得锁它就马上返回否则它将自旋在那里直到该自旋锁保持者释放这时它获得锁并返回总的只有它获得锁才返回
CODE:spin_lock_irqsave(lock, flags)



该宏获得自旋锁同时把标志寄存器值保存到变量flags中并失效本地中断
CODE:spin_lock_irq(lock)







该宏类似于spin_lock_irqsave只是该宏不保存标志寄存器禁止本地中断并获取指定
CODE:spin_lock_bh(lock)



该宏在得到自旋锁同时失效本地软中断
CODE:spin_unlock(lock)



该宏释放自旋锁lock它和spin_trylock或spin_lock配对使用如果spin_trylock返回假表明没有获得自旋锁因此不必使用spin_unlock释放
CODE:spin_unlock_irqrestore(lock, flags)



该宏释放自旋锁lock同时也恢复标志寄存器值为变量flags保存它和spin_lock_irqsave配对使用
CODE:spin_unlock_irq(lock)



该宏释放自旋锁lock同时并激活本地中断它和spin_lock_irq配对应用
CODE:spin_unlock_bh(lock)



该宏释放自旋锁lock同时也使能本地软中断它和spin_lock_bh配对使用
CODE:spin_trylock_irqsave(lock, flags)



该宏如果获得自旋锁lock它也将保存标志寄存器值到变量flags中并且失效本地中断如果没有获得锁它什么也不做 因此如果能够立即获得锁它等同于spin_lock_irqsave如果不能获得锁它等同于spin_trylock如果该宏获得自旋锁lock那需要使用spin_unlock_irqrestore来释放
CODE:spin_trylock_irq(lock)



该宏类似于spin_trylock_irqsave只是该宏不保存标志寄存器如果该宏获得自旋锁lock需要使用spin_unlock_irq来释放
CODE:spin_trylock_bh(lock)



该宏如果获得了自旋锁它也将失效本地软中断如果得不到锁它什么也不做因此如果得到了锁它等同于spin_lock_bh如果得不到锁它等同于spin_trylock如果该宏得到了自旋锁需要使用spin_unlock_bh来释放
CODE:spin_can_lock(lock)



该宏用于判断自旋锁lock是否能够被锁它实际是spin_is_locked取反如果lock没有被锁它返回真否则返回假该宏在2.6.11中第次被定义在先前内核中并没有该宏 自旋锁基本使用如下:
CODE:spinlock_t myr_lock = SPIN_LOCK_UNLOCKED; spin_lock(&myr_lock); /*临界区*/ spin_unlock(&myr_lock);



自旋锁在同时刻至多被个执行线程持有所以个时刻只能有个线程位于临界区这就为多处理器提供了防止并发访问所需保护机制但是在单处理器上编译时候不会加入自旋锁它仅仅被当作个设置内核抢占机制是否被启用开关注意Linux内核实现自旋锁是不可递归点区别于自旋锁在其他操作系统中实现如果你想得到个你正持有你必须自旋等待你自己释放这个锁但是你处于自旋忙等待中所以永远没有机会释放锁于是你就被自己锁死了定要注意! 自旋锁可以用在中断处理但是在使用时定要在获取锁的前首先禁止本地中断(当前处理器上中断)否则中断处理就可能打断正持有锁内核代码有可能会试图支争用这个已经被持有自旋锁这样中断处理就会自旋等待该锁重新可用但是锁持有者在这个中断处理执行完毕的前不可能运行这就会造成双重请求死锁 自旋锁和下半部:由于下半部(中断下半部)可以抢占进程上下文中代码所以当下半部和进程上下文共享数据时必须对进程上下文中共享数据进行保护所以需要加锁同时还要禁止下半部执行同样由于中断处理可以抢占下半部所以如果中断处理和下半部共享数据那么就必须在获取恰当同时还要禁止中断对于软中断无论是否同种类型如果数据被软中断共享那么它必须得到锁保护同种类型两个软中断也可以同进运行在个系统多个处理器上但是个处理器上个软中断绝不会抢占另个软中断因此根本不需要禁止下半部



Tags:  深入理解linux内核 linux内核 linux自旋锁 linux内核机制

延伸阅读

最新评论

发表评论