RCU-5——RCU案例汇总

基于 Linux-5.10

一、经典(可抢占)RCU

1. 例子-RCU链表

假设链表节点和头结点如下:

typedef struct {
    struct list_head link;
    struct rcu_head rcu; //used for call_rcu()
    int key;
    int val;
} test_entry;

struct list_head test_head;

读者访问链表方法如下:

复制代码
int test_read(int key, int *val_ptr)
{
    test_entry *entry;
    int found = 0;

    rcu_read_lock();
    list_for_each_entry_rcu(entry, &test_head, link) {
        if (entry->key == key) {
            *val_ptr = entry->val;
            found = 1;
            break;
        }
    }
    rcu_read_unlock();

    return found;
}
复制代码

1.1. 如果只有一个写者,那么写者是不需要使用锁进行保护的,添加、更新、删除的操作实现方法如下:

(1) 写者添加一个节点到链表尾部

void test_add_node(test_entry *entry)
{
    list_add_tail_rcu(&entry->link, &test_head);
}

(2) 写者更新一个节点

更新的过程是:首先把旧的节点复制更新,然后使用新节点替换旧节点,最后使用函数 call_rcu() 注册回调函数,延后释放旧节点。

复制代码
void test_update_node(int key, int new_val)
{
    test_entry *entry, *new_entry;
    int ret = -ENOENT;

    list_for_each_entry(entry, &test_head, link) {
        if (entry->key == key) {
            new_entry = kmalloc(sizeof(test_entry), GFP_ATOMIC);
            if (new_entry == NULL) {
                ret = -ENOMEM;
                break;
            }

            *new_entry = *entry;
            new_entry->val = new_val;
            list_replace_rcu(&entry->link, &new_entry->link);
            call_rcu(&entry->rcu, test_free_node);
            ret = 0;
            break;
        }
    }

    return ret;
}

void test_free_node(struct rcu_head *head)
{
    test_entry *entry = container_of(head, test_entry, rcu);
    kfree(entry);
}
复制代码

(3) 写者删除一个节点

第一种方法:首先将节点从链表中删除,然后使用函数 call_rcu() 注册回调函数延后释放节点。

复制代码
int test_del_node(int key)
{
    test_entry *entry;
    int found = 0;

    list_for_each_entry(entry, &test_head, link) {
        if (entry->key == key) {
            list_del_rcu(&entry->link);
            call_rcu(&entry->rcu, test_free_node); //不会休眠
            found = 1;
            break;
        }
    }

    return found;
}
复制代码

第二种方法:首先把节点从链表中删除,然后使用 synchronize_rcu() 等待宽限期结束,最后释放节点。

复制代码
int test_del_node(int key)
{
    test_entry *entry;
    int found = 0;

    list_for_each_entry(entry, &test_head, link) {
        if (entry->key == key) {
            list_del_rcu(&entry->link);
            synchronize_rcu(); //会休眠
            kfree(entry);
            found = 1;
            break;
        }
    }

    return found;
}
复制代码

 

1.2. 如果有多个写者,那么写者之间必须使用锁互斥,添加、更新、删除的操作实现方法如下:

(1) 写者添加一个节点到链表尾部,假设使用 spin_lock 保护链表,视情况也可以使用其它互斥锁。

void test_add_node(test_entry *entry)
{
    spin_lock(&test_lock); //struct spinlock test_lock;
    list_add_tail_rcu(&entry->link, &test_head);
    spin_unlock(&test_lock);
}

(2) 写者更新一个节点

复制代码
void test_update_node(int key, int new_val)
{
    test_entry *entry, *new_entry;
    int ret = -ENOENT;

    spin_lock(&test_lock);
    list_for_each_entry(entry, &test_head, link) {
        if (entry->key == key) {
            new_entry = kmalloc(sizeof(test_entry), GFP_ATOMIC);
            if (new_entry == NULL) {
                ret = -ENOMEM;
                break;
            }

            *new_entry = *entry;
            new_entry->val = new_val;
            list_replace_rcu(&entry->link, &new_entry->link);
            call_rcu(&entry->rcu, test_free_node);
            ret = 0;
            break;
        }
    }
    spin_unlock(&test_lock);

    return ret;
}
复制代码

(3) 写者删除一个节点

复制代码
int test_del_node(int key)
{
    test_entry *entry;
    int found = 0;

    spin_lock(&test_lock);
    list_for_each_entry(entry, &test_head, link) {
        if (entry->key == key) {
            list_del_rcu(&entry->link);
            call_rcu(&entry->rcu, test_free_node); //不会休眠
            found = 1;
            break;
        }
    }
    spin_unlock(&test_lock);

    return found;
}
复制代码

使用 spin_lock 进行保护,释放就不能使用会导致睡眠的同步等待宽限期结束的 synchronize_rcu() 函数了。

 

二、加速RCU

TODO


三、可抢占RCU

TODO


四、可休眠RCU

TODO

 

posted on   Hello-World3  阅读(193)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2019-04-27 LED硬件访问服务(1)——AS App编写

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示