我正在研究非垃圾收集环境(如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的所有这些注意事项表明它在库代码中使用起来并不容易,而不是应用程序代码?
答案 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>
注释的关键部分中的共享对象。
这种差异意味着:
QSBR可以胜过EBR,因为可以使用频率较低的同步。是的,正如您所说,QSBR可以与EBR类似的方式使用,但这并不能提供QSBR声称的效率。
在复杂的应用程序中,识别静止状态可能很困难。这就是为什么基于静态的技术(如RCU使用)主要局限于存在自然静止状态的特定环境(例如Linux内核中的上下文切换)。