Linux RCU Q&A

Linux RCU Q&A


Q1: Linux RCU是什么

A: Read-Copy-Update, 是Linux内核里的一种"锁"机制, 可以保证并发读的时候基本无加锁的等待, 不同于rwlock, RCU在写入的时候也可以读

Q2: RCU是如何执行写入操作的

A: RCU在写入的时候, 采用以下步骤(需要修改的内容在结构体A内):

  1. 新建一个结构体, 将原结构体A拷贝到新结构体内(Copy),
  2. 根据需要修改结构体的内容(Update),
  3. 然后将原来指向该结构体的指针指向新的结构体. 此时原结构体A出现两份
  4. 待所有读操作完成后, 删除原结构体, 这样结构体A只有一份最新的

以链表为例:

  1. 初始状态: A--->B--->C
  2. copy: B' = malloc(sizeof(B)); B' <= B
  3. update: B'->x = value; 此时存在A, B, C和B', A--->B--->C, B'--->C, 这里借用了赋值操作的原子性
  4. 修改指针, 得到: A--->B'--->C, B--->C
  5. 待所有对于B的读操作完成后, free(B), 此时变为A--->B'--->C
    由此可见写操作的损耗是比较大的, 涉及到内存分配, 内存拷贝等操作

Q3: RCU是如何执行读操作的

A: 仍然以前面的链表为例:

  1. 在步骤4之前发生的读操作, 获取到的是B, 在读操作期间, B不会被释放, 读操作可以正常完成
  2. 在步骤4之后发生的读操作, 获取到的是新的B', 同样可以正常完成操作
  3. 只有在步骤4之前发生的读操作完成后, B才会被释放, 此时是安全的
    由此可见读操作完全可以并发, 原则上是不需要加锁的, RCU唯一要判断的是"步骤4之前发生的读操作完成"这一条件

Q4: 那么, 如何判断读操作已完成?

A: 内核提供了两个rcu api: rcu_read_lock和rcu_read_unlock, 两者之间的内容就是对于rcu保护对象的读操作
前面链表例子的步骤5会释放结构体B, 如果此时对于B还有引用, 后续会导致异常, 因此这一步操作必须确认读操作已经调用rcu_read_unlock.
从代码可以看出rcu_read_lock是关闭内核抢占, 而rcu_read_unlock是打开内核抢占, 因此RCU确保了读操作期间内核是禁用抢占的(对于当前这个CPU核), 那么写操作在释放原结构体之前, 可以尝试去抢占每个核, 如果每个核都能抢占到, 说明每个核的内核抢占都打开着, 也说明所有的核都没有正在读的操作.
当然在轮询每个核的时候, 已经轮询过的核, 有可能有新的读操作又进来, 这是没有关系的, 从前面链表操作可以看出, 步骤4已经修改了链表, B'已经占据了B的位置, 新的读操作不会访问到B
RCU提出的是一种机制, 轮询只是一种实现方式, Linux内核提供的相应接口为synchronize_rcu, 这个api会阻塞写操作, 直到完成前面的检测. 如果写操作不允许阻塞, 如果不想阻塞, 可以调用call_rcu接口, 这种情况不会阻塞, 但是会注册一个回调函数, 当判断读操作全部完成时, 会调用回调函数, 完成释放指针之类的操作.
多核之间RCU读写流程如下:

CPU 0 CPU 1 CPU 2
rcu_read_lock()
enters synchronize_rcu()
rcu_read_lock()
rcu_read_unlock()
exits synchronize_rcu()
rcu_read_lock()

Q5: 并发写操作是否要加锁?

A: 从内核文档看, 写操作在修改原指针的时候是需要加锁的, 用spinlock即可, 主要是为了防止多个CPU核在更新结构体时造成的冲突, 同样以链表为例, 如果不加锁, 在A--->B修改为A--->B'之前, 多个写操作可能都得到的是B对象, 同时可能导致修改不一致的冲突出现. 所以内核里推荐的读写操作如下:

struct el {
  struct list_head list;
  long key;
  spinlock_t mutex;
  int data;
  /* Other data fields */
};
spinlock_t listmutex;
struct el head;
int search(long key, int *result)
{
  struct list_head *lp;
  struct el *p;
  rcu_read_lock();
  list_for_each_entry_rcu(p, head, lp) {
    if (p->key == key) {
      *result = p->data;
      rcu_read_unlock();
      return 1;
    }
  }
  rcu_read_unlock();
  return 0;
}
int delete(long key)
{
  struct el *p;
  spin_lock(&listmutex);
  list_for_each_entry(p, head, lp) {
    if (p->key == key) {
      list_del_rcu(&p->list);
      spin_unlock(&listmutex);
      synchronize_rcu();
      kfree(p);
      return 1;
    }
  }
  spin_unlock(&listmutex);
  return 0;
}

Q5: 还有什么其他API?

A: RCU还提供另外两个基本的API: rcu_assign_pointer和rcu_dereference.
rcu_assign_pointer完成的是链表操作4中修改指针的操作, 将A--->B--->C改为A--->B'--->C:

rcu_assign_pointer(A->next, typeof(B') B');

rcu_dereference在读操作获取指针地址时使用:

    p = rcu_dereference(A->next);    
    return p->data;  

对于一般的CPU如x86, arm, 这些操作实际上就是简单的赋值

Q6: RCU有什么好处? 在哪用到?

A: 提供并发读操作, 加锁开销可以忽略不计(实际上, 并没有真正的读加锁过程), 但是写操作开销比较大, 因此特别适合读多写很少的场景. 最近在读openvswitch的代码, 流表操作大量用到RCU的功能.

Q7: 更详细的文档?

A: 内核文档/Documentation/RCU/whatisRCU.txt里就有详细的说明, Is Parallel Programming Hard一书中同样用大篇幅介绍了RCU

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容