我试图了解一些内核同步机制的不同用例(顺序锁与RCU(读取 - 复制 - 更新)与每CPU锁)建议用于编写设备驱动程序或内核模块。任何例子都将不胜感激。
答案 0 :(得分:6)
顺序锁这是一种聪明的锁定方法,其中编写者获得自旋锁,读者可以完全避免锁定,代价是不得不重复不一致的读取。这种方法最适用于经常读取数据但很少更新的情况。 这里多次读取不会产生副作用,这与任何读写器锁定和更新类似,不会同时混淆读者。搜索使用/包含API / headers / data结构的内核代码:
#include <linux/seqlock.h>
typedef struct {
unsigned seq; ===> seq is incremented every-time a writer acquires a lock
spinlock_t lock;
} seqlock_t;
write_seqlock(), write_sequnlock()
read_seqlock(), read_sequnlock()
注意:每次编写器获取锁定时,seq no都会递增,读取器,记录seq编号的副本,然后执行读取,重新检查序列号(使用read_seqretry()),如果seq编号是不一致,那么读者必须重新阅读。对于有争议的读者来说,冗余读取并不比“旋转”CPU更糟糕,对于无争议的读者来说,可以一起避免自旋锁。
RCU(读取 - 复制 - 更新)这将更新和回收信息分开,读者和编写者都可以完全避免锁定。 RCU主要用于处理动态分配的数据结构,例如链表。 RCU编写器不会修改数据,而是分配一个新元素,它使用更新的数据进行初始化。
PER-CPU变量这些主要用于CPU特定结构,可以避免全局锁定。请注意,这些仍必须与ISR同步。类似地:
#include <linux/percpi.h>
DEFINE_PER_CPU()
per_cpu(var,cpu)
get_cpu_var(), put_cpu_var()
答案 1 :(得分:2)
读者/作者一致的机制,没有饥饿的作家。这类 锁定数据,读者需要一组一致的信息 并且如果信息发生变化,愿意重试。有两种类型 读者:
- 从不阻止作者的序列阅读器,但他们可能需要重试 如果作者正在通过检测序列号的变化而进行。 作家不等待序列阅读器。
- 锁定读者,如果是作家或其他锁定阅读器,则会等待 正在处理。正在进行的锁定阅读器也会阻止作者 从前进。与常规的rwlock不同,这里的读锁定是 独家,这样只有一个锁定阅读器才能获得它。
醇>这不像brlock那样缓存友好。此外,这可能不会很好 对于包含指针的数据,因为任何编写者都可以 使读者关注的指针无效。
预期的非阻止读者使用:
do { seq = read_seqbegin(&foo); ... } while (read_seqretry(&foo, seq));
在非SMP上,自旋锁消失但作者仍然需要 增加序列变量,因为中断例程可以 改变数据的状态。
在Rusty的Unreliable Guide To Locking中解释了RCU和每CPU锁定。