Linux RCU和双链表

use*_*113 6 c linux rcu

我正在阅读有关Read-copy-update(RCU)的内容.在SMP的情况下,我不确定我是否正确理解它.据我所知,RCU确保以原子方式执行Update.在例如单链表的情况下,显然可以在一个操作中完成与旧元素的交换,因为它是通过改变指针来完成的.但是如何确保在双向链表的情况下RCU仍将以原子方式执行?给定元素有两个指针(next和prev),因此这个元素的每个更改都需要更改这两个指针.如何确保更改这两个指针将作为原子操作完成?如何在Linux中完成?

Adr*_*ien 4

我问自己同样的问题,快速搜索后得到了一条评论的回复,该评论摘自Paul McKenney 撰写的RCU 介绍文章(据我所知,他是 RCU 背后想法的多个并发发明者之一) 。

问题:

我想知道示例中省略反向链接是否是一件好事。这一省略使得这项技术变得微不足道,因为发布只涉及一个指针替换一个指针。

那第二个,后面的,一个呢?如果不支持原子两指针更新,如何执行 p->prev->next = q 和 p->next->prev = q 更新,而不会让客户端面临看到双向链表不一致视图的风险?或者这在实践中不是问题?

不过还是谢谢你的文章。期待下一期!

答案:

很高兴您喜欢这篇文章,并感谢您提出了很好的问题!我可以给出很多答案,包括:在生产系统中,琐碎的技术是一件非常好的事情。向我展示一个示例,其中在 RCU 保护下遍历 ->prev 指针很有用。给出几个这样的例子,我们可以找出如何最好地支持这一点。一致性被严重高估了。(不过,并不是每个人都同意我的观点!)即使使用原子两指针更新,也请考虑以下事件序列: (1) 任务 1 执行 p=p->next (2) 任务 2 在两个任务 1 刚刚处理 (3) 任务 1 确实 p=p->prev 并且未能在开始的地方结束!即使双指针原子更新也无法消除不一致!;-) 如果需要一致性,请使用锁。考虑到上面的例子,我们可以通过简单地按顺序分配指针来支持相当于双指针原子更新的一致性级别——例如,只需从 list_del_rcu() 中删除 prev 指针中毒即可。但这样做会牺牲捕获指针中毒当前捕获的那些错误的能力。

因此,Linux 内核很可能会允许受 RCU 保护的双向链表遍历,但在实现之前我们需要看到对此的迫切需求。

所以基本上,Linux 在进行 RCU 时“不允许”双向向后遍历。正如评论中提到的,您可以使用一些较新的硬件机制,例如Double Compare And Swap,但它们并非随处可用,并且如上所述,您仍然可能会遇到内存一致性问题。