为了简单起见,为了集中讨论我的问题的核心,让我们假设一个由指针变量ptr
本地寻址的内存位置在多个进程之间共享。我特别使用C / ++中的MPI共享内存窗口来分配和共享内存。具体来说,让我们说ptr
引用一个浮点变量,所以在本地我们有
float* ptr;
现在假设所有进程都尝试将相同的值const float f
写入ptr,即
*ptr = f;
我的问题是:这个操作是否需要同步,或者是否可以同时执行,因为所有进程都试图以相同的方式修改字节,即假设f
具有相同的值对于每个过程。因此,我的问题归结为:对于例如并发写操作。浮点变量,有可能竞争条件导致字节模式不一致,尽管每个进程都试图以相同的方式修改内存。即如果我确定每个进程都写入相同的数据,那么我可以省略同步吗?
答案 0 :(得分:1)
是的,您必须同步共享内存。修改线程驻留在不同进程中的事实没有意义,它仍然是数据竞争(从不同线程写入共享内存)。
注意同步对象解决的其他问题,如可见性和内存重新排序,写入共享内存的内容是无关紧要的。
目前,该标准没有定义流程的概念(只有线程),也没有提供任何在流程之间轻松同步的方法。
在共享内存中分配std::mutex
并将其用作同步原语,或者依赖于win32进程间同步原语(如互斥锁,信号量或事件)。
或者,如果您只想同步基元,则可以在共享内存上分配std::atomic<T>
并将其用作同步基元。
答案 1 :(得分:1)
在C ++中,如果多个进程在没有正确使用同步原语或原子操作的情况下写入同一内存位置,则会发生未定义的行为。 (也就是说,它可能会起作用,它可能不起作用,计算机可能会着火。)
在实践中,在您的计算机上,基本上肯定会以您认为应该工作的方式工作。实际上,在某些体系结构上,事情并没有按照预期的方式进行,这似乎是合理的:如果CPU无法读取/写入与共享值一样小的内存块,或者共享值的存储跨越对齐边界,这样的写入实际上也可能涉及读取,而读取 - 修改 - 写入可以具有恢复或破坏对内存的其他更改的效果。
获得所需内容的最简单方法就是将写入视为“放松”的原子操作:
std::atomic_store_explicit(ptr, f, std::memory_order_relaxed);
这确保了写入在不引起数据竞争的意义上是“原子的”,并且除了在*ptr = f
存在潜在问题的体系结构之外不会产生任何开销。