我试图理解rcu_read_lock((同步机制。据我了解,使用 rcu_read_lock((,其中有几个读取线程和一个写入线程,它们读取/写入相同的数据,并且在 rcu_read_lock(( 下执行读取,并且为每个线程复制数据。我写了一个简单的驱动程序来测试这个(read(( 和 write(( 函数是核心(:
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/rcupdate.h>
#include <linux/preempt.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#define MY_MAJOR 42
#define MY_MAX_MINORS 5
char buf[] = "0";
struct dev_data
{
struct cdev cdev;
};
struct dev_data devs[MY_MAX_MINORS];
static ssize_t read(struct file *file, char __user *buffer, size_t size, loff_t *offset)
{
rcu_read_lock();
while (1)
{
printk(KERN_INFO "%s", buf);
}
rcu_read_unlock();
return 0;
}
static ssize_t write(struct file *file, const char __user *buffer, size_t size, loff_t *offset)
{
buf[0] = '1';
return size;
}
const struct file_operations fops = {
.read = &read,
.write = &write,
};
static int __init foo_start(void)
{
int i, err_code;
err_code = register_chrdev_region(MKDEV(MY_MAJOR, 0), MY_MAX_MINORS, "Test char driver");
if (err_code != 0)
return err_code;
for(i=0; i<MY_MAX_MINORS; ++i)
{
cdev_init(&devs[i].cdev, &fops);
cdev_add(&devs[i].cdev, MKDEV(MY_MAJOR, i), 1);
}
return 0;
}
static void __exit foo_end(void)
{
int i;
for(i=0; i<MY_MAX_MINORS; ++i)
{
cdev_del(&devs[i].cdev);
}
unregister_chrdev_region(MKDEV(MY_MAJOR, 0), MY_MAX_MINORS);
}
module_init(foo_start);
module_exit(foo_end);
但是当我在读取过程中调用 write 函数时,数据在 rcu_read_lock(( 下也会发生变化。我的错误在哪里?
附言驱动程序本身很糟糕,但我的目标只是测试 rcu_read_lock((。
您可以在描述它的 kernel.org 上找到 RCU 文档。
它的介绍非常有趣:
虽然RCU实际上很简单,一旦你理解它, 到达那里有时可能是一个挑战。 部分问题在于 过去对RCU的大多数描述都是用错误的写的 假设有"一种真实方式"来描述RCU。 相反 经验是,不同的人必须走不同的道路 以达成对RCU的理解。
如您所见,任何想要真正理解它的人都必须花时间阅读文档。
要了解它的基本概念:
RCU 背后的基本思想是将更新拆分为"删除"和 "填海"阶段。删除阶段删除对数据的引用 数据结构中的项(可能将其替换为 对这些数据项的新版本的引用(,并且可以运行 与读者同时进行。
从文档中阅读更多内容。
现在进入您的问题,以下是rcu_read_lock()
和rcu_read_unlock()
API 函数的描述:
rcu_read_lock((
无效rcu_read_lock(无效(;
由读取器用于通知回收器读取器正在输入 RCU 读取端关键部分。在 RCU 读取端关键部分,尽管内核构建于 CONFIG_PREEMPT_RCU可以抢占 RCU 读取端关键部分。任何 在 RCU 读取端访问的受 RCU 保护的数据结构 关键部分保证全部未回收 该关键部分的持续时间。引用计数可用于 与 RCU 结合使用,以维护对数据的长期引用 结构。
rcu_read_unlock((
无效rcu_read_unlock(无效(;
由读取器用于通知回收器读取器正在退出 RCU 读取端关键部分。 请注意,RCU 读取端严重 部分可以嵌套和/或重叠。
请查看"核心 RCU API 的一些示例用途是什么?"部分,以获得使用它们的代码示例。