我正在阅读Read-copy-update (RCU)。在SMP的情况下,我不确定我是否正确理解它。据我所知,RCU确保以原子方式执行Update。在例如单链表的情况下,显然可以在一个操作中完成与旧元素的交换,因为它是通过改变指针来完成的。但是如何确保在双向链表的情况下RCU仍将以原子方式执行?给定元素有两个指针(next和prev),因此这个元素的每个更改都需要更改这两个指针。 如何确保更改这两个指针将作为原子操作完成? 如何在Linux中完成?
答案 0 :(得分:2)
我问自己同样的问题,快速搜索带来了a reply to a comment,摘自an introduction article to RCU,由Paul McKenney(我收集到的,是这些想法的多个同时发明者之一)在RCU之后)。
问题:
我想知道示例中是否省略了反向链接 好事。由于出版,遗漏使得该技术变得微不足道 只涉及一个替换一个指针。
第二个,后面一个怎么样?不支持原子双指针 更新,如何p-> prev-> next = q和p-> next-> prev = q更新 执行时没有冒险让客户看到不一致的视图 双重链表?或者这在实践中不是问题吗?
谢谢你的文章。期待下一期!
答案:
很高兴你喜欢这篇文章,谢谢你提出的优秀问题!我可以给出任意数量的答案,包括: 在生产系统中,琐碎的技术是一件非常好的事情。 给我看一个例子,它可以在RCU保护下遍历 - > prev指针。鉴于几个这样的例子,我们可以找出最好的支持方法。 一致性被严重高估。 (虽然不是每个人都同意我的意见!) 即使使用原子双指针更新,也要考虑以下事件序列:(1)任务1执行p = p-> next(2)任务2在两个任务1之间插入一个新元素,即刚处理的任务1(3)任务1确实p = p-> prev并且无法在它开始的地方结束!即使双指针原子更新也无法消除不一致! ;-) 如果需要一致性,请使用锁。 鉴于上面的例子,我们可以简单地通过按顺序分配指针来支持等同于双指针原子更新的一致性级别 - 例如,只需从list_del_rcu()中删除prev-pointer中毒。但这样做会牺牲捕获指针中毒当前捕获的那些错误的能力。
因此,Linux内核很可能会在两个方向上允许RCU保护遍历链接列表,但我们需要在实现它之前看到对此的迫切需求。
基本上,Linux"不允许"在做RCU时向后遍历两个方向。正如评论中所提到的,您可以使用一些较新的硬件机制,如Double Compare And Swap,但它们并不是随处可用,如上所述,您仍然可以获得内存一致性问题。