Linux内核中最常见的锁是自旋锁。自旋锁最多只能被一个可执行线程持有。
自旋锁不应该被长时间持有。持有自旋锁的时间最好小于完成两次上下文切换的耗时。
警告:自旋锁是不可递归的!
自旋锁可以使用在中断处理程序中(此外不能使用信号量,因为它们会导致睡眠)。在中断处理程序中使用自旋锁时,一定要在获取锁之前,首先禁止本地中断(当前处理器上的中断请求),否则,中断处理程序就会打断正持有锁的内核代码,有可能试图去争用这个已经被持有的自旋锁。注意,需要关闭的只是当前处理器上的中断。
锁什么?
要知道需要保护的是数据而不是代码。
如果能确定中断在加锁前是激活的,那就不需要在解锁后恢复中断以前的状态了。可以去条件地在解锁时激活中断。
9.2.1 其他针对自旋锁的操作
9.2.2 自旋锁和下半部
函数spin_lock_bh()用于获取指定锁,同时它会禁止所有下半部的执行。
由于下半部都可以抢占进程上下文中的代码,所以当下半部和进程上下文共享数据时,必须对进程上下文中的共享数据进行保护,所以需要加锁的同时还要禁止下半部执行。同样,由于中断处理程序可以抢占下半部,所以如果中断处理程序和下半部共享数据,那么就必须获取恰当的锁的同时还要禁止中断。
同类tasklet不可能同时运行,所以对同类tasklet中的共享数据不需要保护。但是当数据被两个不同种类的tasklet共享时,就需要在访问下半部中的数据前获得一个普通的自旋锁。这里不需要禁止下半部,因为在同一个处理器上决不会有tasklet相互强占的情况。
对于软中断,无论是否同种类型,如果数据被软中断共享,那么它必须得到锁的保护。这是因为即使是同种类型的两个软中断可以同时运行在一个系统的多个处理器上。但是,同一处理器上的一个软中断绝不会抢占另一个软中断,因此,根本没必要禁止下半部。