Linux数据结构之rcu

引言

了解rcu前,先引入一个问题:当多个读者在访问一个全局指针的时候,假设一个写者给全局指针设置了一个新的值,同时需要对旧的指针指向的内存进行销毁。这个时候写着在销毁旧指针的时候,读者可能还在访问该全局变量。
为了解决这个问题,可以通过加锁,或引用计数方式去实现。前者性能不佳;后者会有环形引用的风险;而RCU机制恰到好处。RCU通过机制将写者销毁旧数据的时机延迟到所有读者结束,它具备如下特点:

  • 只针对动态分配,且通过指针访问的数据;
  • 在读临界区不能sleep;
  • 适合对读性能要求很高,对写性能要求不严的场景;
  • 对新旧数据不是特别敏感,追求最终一致性;

1 使用介绍

1.1 定义变量

struct xxx_st __rcu *g_rcu_var;

注:struct的内部字段也可以定义为__rcu

1.2 读访问

rcu_read_lock();
struct xxx_st* xxx_tmp = rcu_dereference(g_rcu_var);
# 略略略... ...
rcu_read_unlock();

注:在rcu_read_lock/rcu_read_unlock之间不能阻塞,不能睡眠

1.3 写访问

进程上下文:

spin_lock(&g_var_lock);
struct xxx_st* xxx_old_ptr = rcu_dereference_protected(g_rcu_var, lockdep_is_held(&g_var_lock));
rcu_assign_pointer(g_rcu_var, xxx_new_ptr);
spin_unlock(&g_var_lock);

if(xxx_old_ptr) {
    synchronize_rcu();
    kfree(xxx_old_ptr);
}

中断上下文:

//struct xxx_st中嵌套struct rcu_head
struct xxx_st {
    # 略略略... ...
    struct rcu_head rhead;
    # 略略略... ...
};
//销毁回调
static void xxx_free_rcu(struct rcu_head *rcu) {
    struct xxx_st* xxx_ptr = container_of(rcu, struct xxx_st, rhead);
    kfree(xxx_old_ptr);
}
//移除操作
spin_lock(&g_var_lock);
struct xxx_st* xxx_old_ptr = rcu_dereference_protected(g_rcu_var, lockdep_is_held(&g_var_lock));
rcu_assign_pointer(g_rcu_var, xxx_new_ptr);
spin_unlock(&g_var_lock);

if(xxx_old_ptr) {
    call_rcu(&xxx_old_ptr->rhead, xxx_free_rcu);
}

注:g_var_lock还可以为struct mutex

1.4 同步

当rcu定义module代码中,假设上面的xxx_free_rcu调用时模块已经卸载,系统就会崩溃。所以在模块卸载时需要执行rcu_barrier进行同步等待数据销毁完毕后再执行退出。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值