信号量semaphore
down_interruptible故名思义是可以被中断的(这也是为什么要检查返回值的原因),而与之对应的是down无法被中断,这个接口是一般不用的。
读写信号量rwsem( read/write semaphore )
接口命名上与信号量类似。
completion
completion用于“在当前线程这外初始化某个活动,然后等待该活动完成”,接口主要是:wait_for_completion与complete/complete_all,另外“completion通常是一个单次(one-shot)设备;也就是说,它只会被使用一次后被丢弃”。
自旋锁spinlock
自旋锁其实就是只能有两个值——锁定或解锁的锁机制,若锁被别人获得,代码将进入忙循环重复检查锁,这就是“自旋”的由来。
要注意的是:自旋锁在忙等待过程中是不可被中断的——也正是因为此,自旋锁只适合用于临界区十分短小的情况,不过虽然看起来效率低下,实则比异步唤醒要快的多;获得自旋锁后,不可以使用可能导致当前进程进入阻塞的代码(但书说临界区内代码都必须是原子,有这个必要?),准确的说是不能以除响应中断外的任何原因放弃本地处理器,有的甚至连中断也可以不响应(但最好不要禁用中断);自旋锁仅在SMP中有效;自旋锁的两种形式:完全锁(full lock)和读写锁。
自旋完全锁的锁接口有四个:spin_lock就是最普通的;spin_lock_irqsave和spin_lock_irq都是屏蔽本地中断的,区别在于前面会记录当前的中断情况,而后者“会假设中断状态”;spin_lock_bh不屏蔽硬中断但屏蔽信号、tasklet、底半部。而解锁接口与锁接口一一对应也有四个,接口名中将lock换为unlock即可。
预防锁出错的方法
对在使用锁的地方增加注释说明;在使用多个锁的地方,注意锁顺序。
免锁算法
原子变量 通过atomic_t声明的int变量,初始化后的对其读写,加减,测试操作只要调用与之对应的atomic接口,则这些操作都是原子的。在实现上,由于C不能实现原子操作,故不同的低层架构有着不同的实现方法,有的是使用汇编,有的使用C加上local_irq_save和local_irq_restore禁用中断。虽归为免锁算法,但也有将这种方法称为原子锁的。
位操作 与原子变量类似,由专门的接口用于读写,位测试等接口保证其位操作的原子性。
seqlock 使用的前提为:1.读操作远多于写操作;2.共享资源内不含有指针或者不会对指针进行任何读写操作。原理是在进入共享区时,系统给一个无符号整形数,进程在完成操作后,会与系统比较该数,若相同则无写操作发生,结束;若不同,则说明有写操作发生,重做。这样就可以免去锁机制了。
RCU(read-copy-update)在需要修改时,先整个复制下来,然后直接修改副本,待原版无引用时,再完成替换。可以看出,类似seqlock,也是针对多读少写的情况。
PS:除了LDD,还主要参考了linux同步方法剖析一文。