在多核和多CPU环境中mmap线程安全性

时间:2015-02-27 14:24:45

标签: c multithreading multiprocessing multicore mmap

在共享内存方面,我对多核和多CPU环境之间的实际问题感到有些困惑,特别是对C语言中的mmap的引用。

我有一个应用程序利用mmap在两个进程之间共享多个内存段。每个流程都可以访问:

  1. 状态和控制内存段
  2. 原始数据(最多8个独立的原始数据缓冲区)
  3. 状态和控制段主要用作IPC。 IE,它可能表示缓冲区1已准备好接收数据,或缓冲区3已准备好进行处理,或者状态和控制存储器段被父级或子级等更新时被锁定。

    我的理解是,如果我错了,请纠正我,就是在单一的PC类型基础设施上的多核CPU环境中,mmap是安全的。也就是说,无论CPU中的内核数量多少,RAM都只能在任何时候由单个内核(或进程)访问。

    单进程RAM访问的假设是否也适用于多CPU系统?也就是说,一个具有多个CPU的PC风格板(我猜,每个CPU中有多个内核)。

    如果没有,我将需要认真重新考虑我的逻辑,以允许多CPU的单人登机!

    任何想法都将不胜感激!

    PS - 单人登机我的意思是一个单独的PC风格系统。这不包括大型机等......只是为了澄清:)

4 个答案:

答案 0 :(得分:3)

  

任何时候RAM都只能被一个核心(或进程)访问。

退一步思考你的假设意味着什么。从理论上讲,是的,这种说法是正确的,但我认为这并不意味着你的意思。除了“如果两个CPU同时写入同一地址,内存不会着火”,你可以从中得出实际的结论。让我解释一下。

如果一个CPU /进程写入内存位置,则不同的CPU /进程写入同一位置,内存写入不会同时发生,它们将一次发生一个。你通常不能推断哪一个写入会在另一个之前发生,你无法推断在从另一个CPU写入之前是否会发生一个CPU的读取,一个较旧的CPU你甚至无法推理多个字节(实际上是多字)值将一次存储/访问一个字节或一次存储多个字节(这意味着对多字节值的读取和写入可以在CPU或进程之间交错)。

这里多个CPU的唯一变化是内存读写顺序。在单个CPU读取存储器上,您可以非常确定从内存中读取的内容将会更早地写入同一内​​存(如果没有其他硬件正在读取/写入内存,则所有注意都将关闭)。在多个CPU上,对不同内存位置的读写顺序会让您感到惊讶(cpu 1写入地址1然后写入2,但cpu 2可能只看到地址2处的新值和地址1处的旧值)。 p>

因此,除非您拥有来自操作系统和/或CPU制造商的特定文档,否则您无法做出任何假设(除非两次写入同一内​​存位置时发生一次,否则将发生在另一次内存之前)。这就是为什么你应该使用来自C11的pthreads或stdatomic.h这样的库来进行正确的锁定和同步,或者真正深入研究CPU文档中最复杂的部分,以真正理解将要发生的事情。 pthreads中的锁定原语不仅提供锁定,还保证内存正确同步。 stdatomic.h是保证内存同步的另一种方法,但是你应该仔细阅读C11标准,看看它承诺的内容和它不承诺的内容。

答案 1 :(得分:1)

一个潜在的问题是每个核心都有自己的缓存(通常只是level1,因为level2和level3缓存通常是共享的)。每个cpu也有它自己的缓存。但是,大多数系统都可以确保缓存一致性,因此这不是问题(除了由于每个核心或处理器写入缓存行中共享的同一内存而导致缓存不断失效的性能影响)。

真正的问题是,由于编译器和/或硬件的优化,无法保证不会重新排序读写操作。您需要使用Memory Barrier清除任何挂起的内存操作,以同步线程的状态或进程的共享内存。如果使用其中一种同步类型(如事件,互斥锁,信号量等),则会出现内存屏障。并非所有共享内存读取和写入都需要是原子的,但在访问可能由另一个线程和/或进程更新的任何共享内存之前,您需要在线程和/或进程之间使用同步。

答案 2 :(得分:0)

  

我的理解是,如果我错了,请纠正我,就是在单一的PC类型基础设施上的多核CPU环境中,mmap是安全的。也就是说,无论CPU中的内核数量多少,RAM都只能在任何时候由单个内核(或进程)访问。

即使某些特定架构也适用,但这种假设通常是完全错误的。您应该在修改共享内存段的进程之间进行适当的同步,除非使用原子内在函数并且算法本身是无锁的。

我建议你将pthread_mutex_t放在共享内存段中(在所有进程中共享)。您必须使用PTHREAD_PROCESS_SHARED属性初始化它:

pthread_mutexattr_t mutex_attr;
pthread_mutexattr_init(&mutex_attr);
pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(mutex, &mutex_attr);

答案 3 :(得分:0)

这对我来说听起来不对。两个不同内核上的两个进程可以同时加载和存储数据到RAM。除此之外,缓存策略还可能导致各种陌生感。因此,请确保使用(进程间)同步对象正确同步对共享内存的所有访问。