C++ 原子比较,多处理器,C/C++;(Linux)

C++ 原子比较,多处理器,C/C++;(Linux),c++,c,linux,shared-memory,atomicity,C++,C,Linux,Shared Memory,Atomicity,我在多处理器系统的共享内存x中有一个变量 其他进程(可能在不同的处理器上)将使用gcc内置的原子操作(如同步、布尔、比较、交换等)写入x 我想我遇到了一些缓存并发性问题,有时需要一些时间才能用新值更新x 我想要的是一种原子比较(没有交换),如果这样的东西存在的话?或者“原子读取”。最快的方法是什么?(避免互斥、锁等) 谢谢 编辑: 我刚刚意识到一个有点粗俗的解决方法是使用uu sync_val_compare_和_swap与一个我知道永远不可能的值。这能解决问题吗?(有没有更干净的方法?) 最快

我在多处理器系统的共享内存x中有一个变量

其他进程(可能在不同的处理器上)将使用gcc内置的原子操作(如同步、布尔、比较、交换等)写入x

我想我遇到了一些缓存并发性问题,有时需要一些时间才能用新值更新x

我想要的是一种原子比较(没有交换),如果这样的东西存在的话?或者“原子读取”。最快的方法是什么?(避免互斥、锁等)

谢谢

编辑:

我刚刚意识到一个有点粗俗的解决方法是使用uu sync_val_compare_和_swap与一个我知道永远不可能的值。这能解决问题吗?(有没有更干净的方法?)

最快的方法是什么?(避免互斥、锁等)

我很确定你不想避免互斥。linux的futexes允许您利用比较和交换的优点(大多数情况下),同时保持经典的互斥语义(发生的“交换”是互斥的一种,而不是受其保护的代码/数据)。我强烈建议您尝试这些方法并分析解决方案(
perf
oprofile
、VTune等),看看您的瓶颈是否真的与锁定机制本身有关,而不是缓存利用率、内存吞吐量、CPU周期、IO访问、远程节点内存访问等

我想我遇到了一些缓存并发性问题,有时需要一些时间才能用新值更新x

好吧,假设您确实需要在处理器之间进行交互,并且您已经测量了futexes对延迟的影响,并且您已经确定它无法满足您的应用程序的需要。因此,如果是这样的话,一个相对合理的处理方法可能是这样的:创建一个32位整数数组,填充的距离大于或等于目标缓存线的大小。使用当前正在执行的CPU和缓存线大小作为此列表中实际值的索引(因此,如果缓存线为64字节,则将CPU扩展16以跳过填充)。您应该只从适当的CPU写入这些值,并且可以从任何其他CPU轮询这些值(可能应该调用繁忙等待正文中CPU的“暂停”指令之一)。这将是检查不同执行线程是否达到/满足给定条件的有效机制

我应该补充一点,这几乎肯定会起作用(有效地用CPU效率换取可能更低的延迟),但对于除非常特殊的一组硬件之外的所有硬件来说,这仍然是一个非常脆弱的解决方案

我想要的是一种原子比较(没有交换),如果是这样的话 有东西存在吗?或者“原子读取”

比较已经是原子的了。这是一个单一的阅读


如果处理器之间的延迟已经很糟糕,那么代码将从解耦中获益。也就是说,稍微分离出依赖项,这样您就不会在内部循环中依赖这种通信。

新的C标准C11具有处理这种情况的
\u原子数据类型和操作。这个标准还没有实现,但是gcc和clang已经很接近了,他们已经实现了这个功能。事实上,
\uuuuuu sync\ubool\ucompare\u和\uswap
功能就是其中的一部分。我已经将其包装到一个可以让您使用C11接口编程的程序中


C11函数的作用是
原子加载
,或者如果您对一致性
原子加载有特殊要求
。正如您所怀疑的那样,P99映射了
\uuu sync\u val\u compare\u和\u swap(&x,0,0)
。然后,如果您查看在大多数体系结构上生成的汇编程序,在
x
成为
int
的情况下,这将在一个简单的加载操作中转换。但是语言并不能保证这一点,这取决于编译器是否知道这些事情,并合成保证是原子的指令。

仅供参考,volatile实际上不会为多线程程序做任何你希望它做的事情。请参阅:不,不能保证C级别上的一个加载操作只转换为一个低级别读取。在大多数体系结构上,它将用于
int
,但不能保证这一点。即使在linux上,互斥锁也不会过度使用。现代C语言对此有一个答案,它比你们想象的更接近Switch的估计值。
void MyFunction(volatile int* x) {
  if (*x != 0) {
     // do something
  }
}