c - 读/写原子性是否适用于多计算机内存?

标签 c race-condition pci

我在多计算机环境中工作,其中 2 台计算机将通过 32 位 PCI 总线访问同一内存。

第一台电脑只会写入32bit int。
*int_pointer = number;

第二台电脑只会读取32位的int。
number = *int_pointer;

两个操作系统/CPU 都是 32 位架构。
带有 PCI 的计算机是基于 Intel 的。
PCI卡上的计算机是power PC。

我担心的情况是,如果只写计算机在读取计算机读取它的同时更改变量,导致读取计算机的数据无效。
我想知道在多台计算机上是否保留了读取/写入内存中相同位置的原子性。

如果是这样,以下是否会阻止竞争条件:

number = *int_pointer;
while(*int_pointer != number) {
    number = *int_pointer;
}

我可以保证写入每 16ms* 发生一次,读取随机发生。

*由于两台计算机的计时器不同,时间会有所漂移。

最佳答案

没有足够的信息来明确回答这个问题。

如果任何一个 CPU 决定将内存缓存在 *int_pointer 处,这将始终失败,并且您的额外代码将无法修复任何竞争条件。

假设两个 CPU 都知道 *int_pointer 处的内存是不可缓存的,并且该位置 *int_pointer 在 4 字节/32 上对齐-位边界 AND PCI 卡上的 CPU 具有 32 位内存接口(interface),AND 指针声明为指向 volatile 并且您的两个 C 编译器都正确实现了 volatile,那么更新很可能是原子的。

如果不满足上述任何条件,结果将不可预测,您的“种族检测”代码可能无法正常工作。

编辑以解释为什么需要 volatile:

这是使用 -O4 且没有 volatile 限定符编译为 MIPS 汇编程序的竞争条件代码。 (我使用了 MIPS,因为生成的代码比 x86 代码更容易阅读):

int nonvol(int *ip) {
  int number = *ip;
  while (*ip != number) {
    number = *ip;
  }
  return number;
}

反汇编输出:

        00000000 <nonvol>:
   0:   8c820000        lw      v0,0(a0)
   4:   03e00008        jr      ra

编译器已经优化了 while 循环,因为它知道 *ip 不能改变。

下面是 volatile 和相同的编译器选项会发生什么:

int vol(volatile int *ip) {
  int number = *ip;
  while (*ip != number) {
    number = *ip;
  }
  return number;
}

反汇编输出:

        00000008 <vol>:
   8:   8c820000        lw      v0,0(a0)
   c:   8c830000        lw      v1,0(a0)
  10:   1443fffd        bne     v0,v1,8 <vol>
  14:   00000000        nop
  18:   03e00008        jr      ra

现在 while 循环没有被优化掉,因为使用 volatile 告诉编译器 *ip 可以随时改变。

关于c - 读/写原子性是否适用于多计算机内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16660489/

相关文章:

c - 如何通过 C89 检查文件是否存在?

c++ - 为什么没有返回语句时没有任何编译器错误?

c++ - 避免统计和重命名之间的 TOCTOU(检查时间,使用时间)竞争条件

javascript - JavaScript中的数据竞赛?

linux - 为什么没有分配给 pci 设备的 BAR 地址?

c - MPI有超时机制吗?

c - 在 glibc 上覆盖 pthread 函数但在 musl 上不覆盖时出现神秘的段错误

c# - 我怎么知道什么时候调用 Dispose 是安全的?

PCIe 64 位不可预取空间

caching - DMA/Microblaze 直接访问用户空间页面物理地址后读取错误数据(内核分散/聚集)