自旋锁的选择
参考:《Linux Kernel Development》3ed_CN p-149 扩展
如下内容中没有涉及读写自旋锁,尝试锁的获取等,只包含一般情形;如下是我的总结,如有误,请指出:
自旋锁在不同情况下的选择:
1、进程上下文与进程上下文之间:
spin_lock()
2、进程上下文与中断上半部之间:
spin_lock_irqsave() or spin_lock_irq()
3、进程上下文与中断下半部之间:
spin_lock_bh()
4、中断上半部与中断上半部之间:
spin_lock_irqsave() or spin_lock_irq()
5、中断上半部与中断下半部之间:
spin_lock_irqsave() or spin_lock_irq()
6、中段下半部与中断下半部之间:
(1)软中断与软中断之间 (同类型或不同类型的软中断可以同时运行在一个系统的多个处理器上,在同一个核上当然不能同时运行)
spin_lock()
(2) 不同类型的tasklet之间(此处只写明是不同类型的tasklet之间,因为同类型的tasklet不可能同时运行)
spin_lock()
在不同的核之间使用spin_lock就可以了,至于其它的全是对同一个核施加的限制;
补充
2013-9-7 21:00
关于读写锁rwlock_t和顺序锁seqlock_t的理论.
参考:《Operating System Concepts》9ed p_220
《CSAPP》2_ed p_1004
分别阐述了 Readers-Writers Problem first readers-writers problem. The first readers-writers problem, which favors readers,requires that no reader be kept waiting unless a writer has already been granted permission to use the object. In other words, no reader should wait simply because writer is waiting. second readers-writers problem. The second readers-writers problem, which favors writers, requires that once a writer is ready to write, it performs its write as soon as possible. Unlike the first problem, a reader that arrives after a writer must wait, even if the writer is also waiting. 根据rwlock_t和seqlock_t的各自实现与用法,可以看出rwlock_t数据结构用于解决first readers-writers problem,seqlock_t数 据结构用于解决second readers-writers problem。
补充
2013-9-6-18:00
引述自:http://www.ibm.com/developerworks/cn/linux/l-synch/part1/ 内容包括:原子操作、信号量、读写信号量、自旋锁的API
查了下大内核锁,看到该页面,内容涵盖了我所做的总结,而且更为细致,请参考原文。
获得自旋锁和释放自旋锁有好几个版本,因此让读者知道在什么样的情况下使用什么版本的获得和释放锁的宏是非常必要的。 1、软中断上下文与进程上下文 (1)如果被保护的共享资源只在进程上下文访问和软中断上下文访问,那么当在进程上下文访问共享资源时,可能被软中断打断,从而可能进入软中断上下文来对被保护的共享资源访问,因此对于这种情况,对共享资源的访问必须使用spin_lock_bh和spin_unlock_bh来保护。 (2)当然使用spin_lock_irq和spin_unlock_irq以及spin_lock_irqsave和spin_unlock_irqrestore也可以,它们失效了本地硬中断,失效硬中断隐式地也失效了软中断。但是使用spin_lock_bh和spin_unlock_bh是最恰当的,它比其他两个快。 (3)如果被保护的共享资源只在进程上下文和tasklet或timer上下文访问,那么应该使用与上面情况相同的获得和释放锁的宏,因为tasklet和timer是用软中断实现的。 2、tasklet与tasklet之间 (1)如果被保护的共享资源只在一个tasklet或timer上下文访问,那么不需要任何自旋锁保护,因为同一个tasklet或timer只能在一个CPU上运行,即使是在SMP环境下也是如此。实际上tasklet在调用tasklet_schedule标记其需要被调度时已经把该tasklet绑定到当前CPU,因此同一个tasklet决不可能同时在其他CPU上运行。timer也是在其被使用add_timer添加到timer队列中时已经被帮定到当前CPU,所以同一个timer绝不可能运行在其他CPU上。当然同一个tasklet有两个实例同时运行在同一个CPU就更不可能了。 (2)如果被保护的共享资源只在两个或多个tasklet或timer上下文访问,那么对共享资源的访问仅需要用spin_lock和spin_unlock来保护,不必使用_bh版本,因为当tasklet或timer运行时,不可能有其他tasklet或timer在当前CPU上运行。 如果被保护的共享资源只在一个软中断(tasklet和timer除外)上下文访问,那么这个共享资源需要用spin_lock和spin_unlock来保护,因为同样的软中断可以同时在不同的CPU上运行。 3、软中断与软中断之间 如果被保护的共享资源在两个或多个软中断上下文访问,那么这个共享资源当然更需要用spin_lock和spin_unlock来保护,不同的软中断能够同时在不同的CPU上运行。 4、软中断与中断上半部;进程上下文与中断上半部 如果被保护的共享资源在软中断(包括tasklet和timer)或进程上下文和硬中断上下文访问,那么在软中断或进程上下文访问期间,可能被硬中断打断,从而进入硬中断上下文对共享资源进行访问,因此,在进程或软中断上下文需要使用spin_lock_irq和spin_unlock_irq来保护对共享资源的访问。 5、中断上半部与中断上半部之间 (1)如果只有一个中断处理句柄访问该共享资源,那么在中断处理句柄中仅需要spin_lock和spin_unlock来保护对共享资源的访问就可以了。因为在执行中断处理句柄期间,不可能被同一CPU上的软中断或进程打断。 (2)如果有不同的中断处理句柄访问该共享资源,那么需要在中断处理句柄中使用spin_lock_irq和spin_unlock_irq来保护对共享资源的访问。 6、关于spin_lock_irqsave与spin_lock_irq (1)在使用spin_lock_irq和spin_unlock_irq的情况下,完全可以用spin_lock_irqsave和spin_unlock_irqrestore取代。 (2)如果可以确信在对共享资源访问前中断是使能的,那么使用spin_lock_irq更好一些,因为它比spin_lock_irqsave要快一些。 (3)如果你不能确定是否中断使能,那么使用spin_lock_irqsave和spin_unlock_irqrestore更好,因为它将恢复访问共享资源前的中断标志而不是直接使能中断。 (4)当然,有些情况下需要在访问共享资源时必须中断失效,而访问完后必须中断使能,这样的情形使用spin_lock_irq和spin_unlock_irq最好。 附: 需要特别提醒读者,spin_lock用于阻止在不同CPU上的执行单元对共享资源的同时访问以及不同进程上下文互相抢占导致的对共享资源的非同步访问,而中断失效和软中断失效却是为了阻止在同一CPU上软中断或中断对共享资源的非同步访问。