【发布时间】:2012-09-13 19:25:48
【问题描述】:
关于内存屏障的使用,我有一些不明白的地方,我希望得到澄清。
所以,假设我们有一个 Treibers 堆栈,但我们使用的是 SMR,所以没有与每个指针关联的计数器 - 我们必须在原子操作中正确获取指针(这与 ABA 无关 - 我们是使用处理 ABA 的 SMR,这不是问题的一部分)。
现在,假设我们正在使用 Intel (x86/x64),因此每个 CAS 都带有完整的内存屏障。我认为当 CASing 时会发生什么情况是缓存行被锁定,发出读取屏障,这会清除无效队列,因此缓存行被加载与该缓存行的最新版本,比较发生,然后发出写屏障,刷新存储缓冲区,最后我们释放缓存行锁。
所以,我们有下面的pop代码;
BARRIER_PROCESSOR_READ;
original_top = stack_state->top;
do
{
if( original_top == NULL )
return( 0 );
copy_of_original_top = original_top;
original_top = compare_and_swap( &stack_state->top, original_top->next, original_top );
}
while( copy_of_original_top != original_top );
*user_data = original_top->user_data;
所以,我们首先发出一个读屏障——这确保我们刷新我们的无效队列。但是这样做和读取 state_state->top 之间存在差距。在清除无效队列和读取 state_stack->top 之间,任何事情都可能发生。核心可以服务中断,发生总线争用并且非常慢,您可以命名它 - 可以重新加载无效缓存行(并由另一个处理器重新无效)。基本上 - 无效队列可以重新填充。这意味着我们实际上不能信任 original_top 的值;我们可能正在读取一个实际上是错误的本地缓存行(我们还没有将其无效化)并且这样做,错误地认为它的值为 NULL 并返回 0。
所以基本上,我看不到读取障碍是如何帮助的,因为在障碍之后但在您希望执行的实际读取之前仍然可能发生任何事情。
我在这里错过了什么?
【问题讨论】:
标签: c concurrency atomic lock-free