【问题标题】:What does rcu_read_lock() actually do (Linux Kernel)rcu_read_lock() 实际做了什么(Linux 内核)
【发布时间】:2019-09-18 08:47:40
【问题描述】:

我正在尝试了解 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);

但是当我在读取过程中调用写入函数时,数据也在 rcu_read_lock() 下发生变化。我的错在哪里?
附:驱动程序本身很糟糕,但我的目标只是测试 rcu_read_lock()。

【问题讨论】:

  • 据我了解,它是一种机制,允许读者读取可能陈旧的,copy某些数据结构,而作者是更新主副本。
  • @IanAbbott:实际上,在 RCU 中,所有部分都是为 writer 的:它读取一个对象,复制它,并更新该副本。之后,为读者发布一个指向副本的指针,而前一个对象仍然存在。
  • @Tsyvarev 是的,抱歉,我没有明确说明作者完成了所有工作。我并不是要暗示读者制作了副本,但我可以看出我写的内容可能具有误导性。
  • 你没有正确使用RCU API

标签: c linux-kernel locking rcu


【解决方案1】:

你可以找到描述它的the RCU documentation on kernel.org

它的介绍真的很有趣:

虽然RCU其实很简单,一旦你理解了它, 到达那里有时可能是一个挑战。部分问题在于 过去对 RCU 的大部分描述都写错了 假设有“一种真实的方式”来描述 RCU。反而, 经验是不同的人必须走不同的道路 了解 RCU。

如您所见,任何想要真正理解它的人都必须花时间阅读文档。

大致了解一下:

RCU 背后的基本思想是将更新拆分为“删除”和 “回收”阶段。删除阶段删除对数据的引用 数据结构中的项目(可能通过将它们替换为 引用这些数据项的新版本),并且可以运行 与读者同时进行。

从文档中了解更多信息。

现在来回答您的问题,这里是 rcu_read_lock()rcu_read_unlock() API 函数的描述:

rcu_read_lock()

void rcu_read_lock(void);

读者用来通知回收者读者正在进入 RCU 读取端临界区。在里面阻止是违法的 一个 RCU 读取端临界区,尽管内核是用 CONFIG_PREEMPT_RCU 可以抢占 RCU 读取端临界区。任何 在 RCU 读取端访问的受 RCU 保护的数据结构 关键部分保证保持未回收的完整 该关键部分的持续时间。引用计数可用于 与 RCU 一起维护对数据的长期引用 结构。

rcu_read_unlock()

void rcu_read_unlock(void);

阅读器用于通知回收器阅读器正在退出 RCU 读取端临界区。请注意,RCU 读取端关键 部分可以嵌套和/或重叠。

查看“CORE RCU API 的一些示例用途是什么?”部分,以便有一个使用它们的代码示例。

【讨论】:

    猜你喜欢
    • 2019-05-14
    • 2013-06-02
    • 2020-11-21
    • 2015-02-26
    • 2017-06-29
    • 2013-06-13
    • 2021-10-25
    • 2011-08-12
    • 1970-01-01
    相关资源
    最近更新 更多