网络代码中广泛使用上锁,本书中每项主题下,可能都会发现上锁的议题,对众多程序设计类型而言,尤其是针对内核的程序设计,互斥,上锁机制以及同步都是一般性主题,而且相当有趣复杂,linux不但引入互斥,而且对一些方法做了优化,本节只总结在网络代码中所见到的上锁机制,建议参阅O Relly 出版的 深入理解linux内核 和linux设备驱动程序中深入而详尽的讨论。
每种互斥机制都是特定环境下的最佳选择,以下是网络代码中常见的互斥方法
回转锁,spinlock
这是一种某一时刻只能一个执行线程持有的锁,如果试图有另一个线程抢占,则会进入循环等待,直到锁被释放。由于进入循环将造成浪费,回转锁只用于多处理器系统,而且通常指用在短期等待的场景,由于会引起其他执行线程的浪费,执行现场在持有回转锁的时候不能休眠。
读写 回转锁
当给定锁的使用可以明确分为只读和读写时,应该先试用读/写回转锁,读回转锁和读写回转锁的差别在于,对读 写回转锁而言,多个读取者可以同时持有该锁,然而,在同一个时刻该锁的持有者只能有一个人可以写入,同时,当该锁背斜入者持有时,读取都不能取得该锁,由于读取者的优先级高于写入,因此当读取者的数目,远远超过写入者数目时,这种锁类型能很好的工作。
当该锁是在只读模式下取得的,不能直接提升成读-写模式。
读取 拷贝 更新 RCU
RCU是linux提供互斥的最新机制之一,在下列特定条件下工作得非常好。
1 与只读锁的请求相比,读-写锁的请求很少见。
2 持有该锁的代码以原子的形式,而且不能休眠。
3 由该锁保护的数据结构是通过指针访问的。
第一个条件及性能, 而另外两个则是RCU工作原理的基础。
注意,第一个条件似乎意味着应该使用读-写回转锁来代替RCU,为了了解恰当使用时,为什么RCU比读-写回转锁更好,需要考虑其他方面,比如SMP 系统上处理器缓存的影响。
RCU设计背后的工作原理简单而且高效,有关RCU优势的清晰描述及其实现的简述,可以参考Paul McKenney 的文章。
RCU在网络代码中使用的实例就是路由子系统,在缓存中查询比更新要频繁,因此,实现路由缓存查询的函数不会在搜索期间被堵塞。