基于静止状态的复垦与基于纪元的复垦

时间:2016-04-12 12:31:11

标签: multithreading algorithm memory-management thread-safety lock-free

我正在研究非垃圾收集环境(如C或C ++)中无锁数据结构的各种类型的内存回收策略。

在我的实验中,我成功实施了一些策略 - 特别是基于静态状态的回收(QSBR)和基于纪元的回收(EBR)。

我的问题涉及这两种策略之间的主要区别之一。

首先,我知道 QSBR EBR 的工作原理,并且已经成功实施了这两种策略。 QSBR和EBR实际上非常相似。它们都是延迟回收策略 - 意思是,它们通过简单地延迟实际释放来释放内存时避免竞争条件,直到可以证明释放内存是安全的。使用QSBR和EBR,使用全局“纪元计数器”,然后为每个参与线程实现各种线程本地纪元计数器。

QSBR和EBR之间的主要区别在于,对于QSBR,您基本上指示线程何时对任何共享数据有任何引用。使用EBR,您可以指示线程 何时引用共享数据。因此,在实践中,使用EBR的代码最终看起来更像传统的互斥锁定/解锁关键部分,如:

enter_critical_section();

/* do some cool lock-free stuff */

exit_critical_section();

......然而,对于QSBR,它更像是:

/* do some cool lock-free stuff */

quiescent_state(); // this thread is done using shared data


所以他们非常相似。但是,我不太了解的一个关键问题是所有文献都表明在实践中,QSBR有一个主要缺点:它需要应用程序级支持,这意味着它不适合使用在通用库中。

无数期刊文章或图书馆文档中提到了这一点,例如在http://www.cs.toronto.edu/~tomhart/papers/tomhart_thesis.pdf中,它说:

  

QSBR依赖于应用程序的事实是根本   QSBR和EBR之间的区别。根据定义,EBR可以检测到恩典   图书馆一级的时期。相比之下,QSBR要求   应用程序报告静态状态到QSBR库。正如我们所展示的那样   第5.2节,这使得QSBR比

具有显着的性能优势

使用QSBR变体的User-space RCU project的文档也说了类似的内容:

  

但是,每个线程必须定期调用rcu_quiescent_state(),   就像在内核中一样,必须定期调用schedule()。   必须执行RCU读取端关键部分的每个线程   在创建线程之后也调用rcu_register_thread()   线程退出前rcu_unregister_thread()。这些要求清楚   对整体应用程序设计施加了严格的限制   例如,禁止在大多数库代码中使用QSBR RCU,但是在   返回,QSBR提供无与伦比的性能。

我很难理解为什么会出现这样的问题。我在这里收集的是,使用QSBR,应用程序需要指示它何时进入静止状态。但是我无法理解为什么这在图书馆层面很难做到?

提供数据结构(如堆栈和队列)的无锁库是否只能表明它在每次操作完成后都进入静止状态?为什么有关QSBR的所有这些注意事项表明它在库代码中使用起来并不容易,而不是应用程序代码?

1 个答案:

答案 0 :(得分:3)

在QSBR quiescent_state()中,可以在调用线程不包含对共享对象的引用的任意位置调用enter_critical_section()。另一方面,在EBR中,线程必须访问由exit_critical_section<dom-module id="sync-data"> <template> <p>Debug info: {scope:[[scope]], key:[[key]], value:[[value]]}</p> </template> <script> (function () { var items = [] var propagateChangeStatus = {} var togglePropagationStatus = function (status) { propagateChangeStatus[this.scope + '|' + this.key] = status } var shouldPropagateChange = function () { return propagateChangeStatus[this.scope + '|' + this.key] !== false } var propagateChange = function (key, scope, value) { if (shouldPropagateChange.call(this)) { togglePropagationStatus.call(this, false) var itemsLength = items.length for (var idx = 0; idx < itemsLength; idx += 1) { if (items[idx] !== this && items[idx].key === key && items[idx].scope === scope) { items[idx].set('value', value) } } togglePropagationStatus.call(this, true) } } Polymer({ is: 'sync-data', properties: { key: { type: String, value: '' }, scope: { type: String, value: '' }, value: { type: String, notify: true, observer: '_handleValueChanged', value: '' } }, created: function () { items.push(this) }, _handleValueChanged: function (newValue, oldValue) { this.typeof = typeof newValue propagateChange.call(this, this.key, this.scope, newValue) } }) })() </script> </dom-module> 注释的关键部分中的共享对象。

这种差异意味着:

  1. QSBR可以胜过EBR,因为可以使用频率较低的同步。是的,正如您所说,QSBR可以与EBR类似的方式使用,但这并不能提供QSBR声称的效率。

  2. 在复杂的应用程序中,识别静止状态可能很困难。这就是为什么基于静态的技术(如RCU使用)主要局限于存在自然静止状态的特定环境(例如Linux内核中的上下文切换)。