rcu_read_lock()到底是做什么的(Linux内核)?

问题描述 投票:2回答:1

我想了解一下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()下也在变化。我的错误在哪里?P.S. 驱动程序本身是crippy,但我的目标只是测试rcu_read_lock()。

c linux-kernel locking rcu
1个回答
0
投票

你可以找到 kernel.org上的RCU文档 其中描述了它。

它的介绍真的很有意思。

虽然RCU实际上很简单,但一旦你理解了它,要达到这个目的有时是个挑战。 部分问题在于,过去对RCU的描述大多是基于一种错误的假设,即有 "一种真正的方法 "来描述RCU。 相反,我们的经验是,不同的人必须通过不同的途径来理解RCU。

正如您所看到的,任何想要真正理解RCU的人都必须花时间阅读文件。

要了解它的基本概念。

RCU的基本思想是将更新分为 "移除 "和 "回收 "两个阶段。移除阶段删除了数据结构中对数据项的引用(可能是用对这些数据项的新版本的引用来替换它们),并且可以与读者同时运行。

从文档中阅读更多内容。

现在来谈谈你的问题,这里是对以下内容的描述。rcu_read_lock()rcu_read_unlock() API函数。

rcu_read_lock()

void rcu_read_lock(void)。

读卡器用来通知取卡器正在进入RCU读边临界段。虽然使用CONFIG_PREEMPT_RCU构建的内核可以预先阻止RCU读侧临界段,但在RCU读侧临界段进行阻塞是非法的。在RCU读边临界段期间访问的任何RCU保护的数据结构,保证在该临界段的整个过程中不会被回收。引用计数可以与RCU结合使用,以保持对数据结构的长期引用。

rcu_read_unlock()

void rcu_read_unlock(void)。

读卡器用来通知取卡器正在退出RCU读边临界段。 请注意,RCU读边临界段可能是嵌套或重叠的。

请看 "什么是核心RCU API的一些示例用法?"一节,以获得使用它们的代码示例。

© www.soinside.com 2019 - 2024. All rights reserved.