以下是来自Essential Linux Device Drivers的直接引用,这可能是您要查找的内容。看来最后一部分涉及RCU的部分可能是你感兴趣的部分。
读写器锁
另一种专门的并发调节机制是自旋锁的读写器变体。如果使用a
关键部分是这样的:单独的线程从共享数据结构读取或写入,但不这样做
这两个锁都是天生的配合。同时在关键区域内允许多个阅读器线程。
读者螺旋锁的定义如下:
rwlock_t myrwlock = RW_LOCK_UNLOCKED;
read_lock(&myrwlock); /* Acquire reader lock */
/* ... Critical Region ... */
read_unlock(&myrwlock); /* Release lock */但是,如果编写器线程进入关键部分,则其他读写器线程不允许进入。使用
作家自旋锁,你会写这个:
rwlock_t myrwlock = RW_LOCK_UNLOCKED;
write_lock(&myrwlock); /* Acquire writer lock */
/* ... Critical Region ... */
write_unlock(&myrwlock); /* Release lock */查看net/ipx/ipx_route.c中存在的IPX路由代码,以了解真实的读写器自旋锁示例。一个
称为ipx_routes_lock的读写器锁保护IPX路由表免受同时访问。主题
需要查找路由表来转发数据包请求读卡器锁。线程需要添加或
从路由表中删除条目获取写入程序锁定。这通常会提高性能
路由表查找的实例远多于路由表更新。
与常规自旋锁一样,读写器锁也具有相应的irq变体 - 即read_lock_irqsave(),
read_lock_irqrestore(),write_lock_irqsave()和write_lock_irqrestore()。这些的语义
函数类似于常规自旋锁的函数。
2.6内核中引入的序列锁或seqlocks是作者喜爱的读写器锁
读者。如果对变量的写入操作远远超过读取访问次数,这非常有用。一个例子是
本章前面讨论的jiffies_64变量。作家线程不会等待可能在里面的读者
一个关键部分。因此,读者线程可能会发现他们在关键部分内的输入失败
并可能需要重试:
u64 get_jiffies_64(void) /* Defined in kernel/time.c */
{
unsigned long seq;
u64 ret;
do {
seq = read_seqbegin(&xtime_lock);
ret = jiffies_64;
} while (read_seqretry(&xtime_lock, seq));
return ret;
}编写者使用write_seqlock()和write_sequnlock()保护关键区域。
2.6内核引入了另一种称为Read-Copy Update(RCU)的机制,该机制可以得到改进
读者人数远远超过作家。基本思想是读者线程可以不执行
锁定。编写器线程更复杂。他们在数据结构的副本上执行更新操作
替换读者看到的指针。原始副本一直保持到下一个上下文切换到所有CPU
确保完成所有正在进行的读取操作。请注意,使用RCU比使用更多的参与
到目前为止讨论过的基元,只有在确定它是适合工作的正确工具时才应该使用。 RCU数据
结构和接口函数在include/linux/rcupdate.h中定义。有足够的文件
Documentation/RCU/*。
有关RCU使用示例,请参阅fs/dcache.c。在Linux上,每个文件都与目录条目相关联
信息(存储在称为dentry的结构中),元数据信息(存储在inode中)和实际数据
(存储在数据块中)。每次操作文件时,文件路径中的组件都将被解析,而
获得相应的细目。该dentries被保存在一个名为dcache的数据结构中
加快未来的行动。在任何时候,dcache查找的次数远远超过dcache更新,因此
使用RCU原语来保护对dcache的引用。