Linux 内核设计了多种锁机制,比如 读写锁、自旋锁 和 信号量 等。为什么要设计这么多锁机制呢?这是因为不同的锁机制适用于不同的场景,比如 读写锁 适用于读多写少的场景;而 信号量 适用于进程长时间占用锁,并且允许上下文切换的场景。
本文主要介绍一种 Linux 内核中性能非常高的锁机制:RCU锁机制。
RCU 是 Read Copy Update 的缩写,中文意思是 读取、复制、更新。RCU锁机制 就是通过读取、复制和更新这三个操作来实现锁功能。在介绍 RCU锁 之前,我们先来看看下面的实例。
struct foo {
int a;
char b;
long c;
};
struct foo *gbl_foo;
void foo_read(void)
{
foo *fp = gbl_foo;
if (fp != NULL)
do_something(fp->a, fp->b, fp->c);
}
void foo_update(foo *new_fp)
{
foo *old_fp = gbl_foo;
gbl_foo = new_fp;
free(old_fp);
}
假如有线程 A 和线程 B 同时执行 foo_read(),而另线程 C 执行 foo_update(),那么会出现以下几种情况:
- 线程 A 和线程 B 同时读取到旧的 gbl_foo 的指针。
- 线程 A 和线程 B 同时读取到新的 gbl_foo 的指针。
- 线程 A 和线程 B 有一个读取到新的 gbl_foo 的指针,另外一个读取到旧的 gbl_foo 的指针。
如果线程 A 或线程 B 在读取旧的 gbl_foo 数据还没完成时,线程 C 释放了旧的 gbl_foo 指针,那么将会导致程序奔溃。
也就是说,在不加锁的情况下,对公共数据的访问是危险的。当然,我们可以使用 读写锁、信号量 或者 自旋锁 来对公共数据进行保护。但这些锁都有各自的弊端,比如:

RCU锁是Linux内核中一种高性能的锁机制,适用于读多写少的场景。它通过宽限期确保在数据更新后所有读者不再使用旧数据,从而安全释放旧数据。在RCU临界区,内核抢占被禁用以防止调度,确保数据一致性。使用RCU锁需在rcu_read_lock()和rcu_read_unlock()之间保护代码,并使用synchronize_kernel()等待所有CPU调度以释放资源。

1834

被折叠的 条评论
为什么被折叠?



