【问题标题】:How can a read memory barrier work in the presence of interrupts?在存在中断的情况下,读内存屏障如何工作?
【发布时间】: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


    【解决方案1】:

    我没有完全理解你的问题,但我强烈怀疑你遗漏了一个细节。

    内存防护用于保证更改的可见性,而不是同步进程。单独的防护不会锁定对数据的访问。

    另一方面,原子操作和锁(如互斥锁或临界区或信号量或任何其他同步原语)都将保证只有一个线程访问给定的内存区域(假设所有访问都被编码为'拥有'这样的锁或原子)。但它们不能保证有序的可见性。

    你需要both独占访问如果你想要两者(注意:fencing通常已经作为高级同步原语的一部分实现,如互斥锁,所以如果你使用那些你不必担心明确的围栏)。

    【讨论】:

      【解决方案2】:

      我不完全确定我理解你的问题,但是,在发出读取障碍之后,任何后续读取肯定会在障碍之前发生的读取之后排序。根据 BARRIER_PROCESS_READ 的定义方式,它还可能强制后续读取从共享内存而不是特定于处理器的高速缓存行中提取数据,其效果是在其他处理器上执行的写入将是可见的(假设这些写入后面跟着一个适当的写屏障!)。

      这些事情在存在中断的情况下仍然成立。即使缓存行在读屏障之后从中断处理程序中被填充,那么从这些缓存行中读取仍然会给你一个相对于读屏障语义有效的值。

      我怀疑在您提供的代码示例中,读取屏障的目的实际上是使其他处理器的写入可见,以确保下一行 - original_top = stack_state->top; - 检索新值而不是具有在屏障之前发生的读取之后被本地缓存。如果中断处理程序读取相同的地址,则此约束仍然成立。读取的值不会“新鲜”,但至少不会是缓存了无限时间的值。

      【讨论】:

      • 嗯。这就是我认为它正在做的事情,但是当涉及到 Micahel & Scott 队列时,这让我感到困惑。我现在想,虽然我明白了(我在想它,现在我想我明白了)。将等待任何其他答案,如果没有更好的,将标记为正确。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-19
      • 1970-01-01
      • 2018-11-29
      • 2019-11-09
      • 2015-04-25
      • 2021-04-27
      相关资源
      最近更新 更多