【问题标题】:One writer, multiple readers in lock-free application无锁应用中的一个写入器,多个读取器
【发布时间】:2015-02-03 15:13:15
【问题描述】:

我正在构建一个程序,其中一个变量仅由一个线程修改(原子上,双向全内存屏障),并读取多个线程。读取线程需要原子读取变量还是简单读取就足够了?

通常(我使用 gcc,但我猜这个概念与语言无关)

int a = 0;

在写作线程中:

__atomic_add_fetch (&a, 1, __ATOMIC_SEQ_CST);

在阅读线程中:

int b = __atomic_load_n (&a, __ATOMIC_SEQ_CST);

/ * OR */

int b = a;

我的猜测是,如果唯一的作家在两个方向上都设置了完整的障碍,那么应该没有竞争条件,但我似乎找不到任何证实...

谢谢!

【问题讨论】:

  • 一个简单的读取将是一个 UB 的数据竞争。
  • UB 代表什么?
  • 这是未定义的行为。
  • 根据代码,编译器可以生成代码以将a 加载到寄存器中一次,并且永远不再引用内存位置。在这种情况下,b(保存在寄存器中)永远不会改变。
  • 这不是一个真正的问题,如果我想阻止它,我可以将它标记为 volatile。更多的是关于值的加载,而不是加载后会发生什么。

标签: c multithreading gcc atomic


【解决方案1】:

为了安全起见,您应该使用 seq_cstacquire 内存模型进行原子加载。编译器或 CPU 可以采取一些技巧来优化缓存或寄存器的使用,并且不会以不同的顺序加载值或加载,因此使用特定于加载的屏障可能是个好主意。

将变量标记为volatile 也会有所帮助。

【讨论】:

  • 我知道这样会更安全,但我必须这样做吗?如果我不想要一个最新的值,那么 volatile 应该不是必需的,不是吗?
  • 没有明确的答案。这取决于你的具体情况。如果您不需要最新值,则可能不需要原子加载。当然,除非编译器/CPU 将其优化到只加载一次并且永远不会重新加载的点(这在某些边界情况下是可能的)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-17
  • 1970-01-01
  • 2012-07-15
相关资源
最近更新 更多