同步mmaped区域访问的正确方法是什么

What is the correct way to synchronize the access of a mmaped region

我需要在不同的进程之间交换一些变量,并通过共享内存尝试。下面的代码是这种尝试的简化版本。该程序按预期运行,但我想确保交换不只是因为运气。

我的主要问题是,是否足以将所有指针声明为 volatile,以确保编译器无法优化内存读取?还是我需要插入一些额外的同步命令?

#include <sys/mman.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <type_traits>

struct Exchange
{
    int x;
};

int main()
{
    int fd = open("/dev/shm/foobar", O_RDWR | O_CREAT, 0600);
    if(fd == -1)
    {
        std::cerr << "Open failed\n";
        return 1;
    }
    if(ftruncate(fd, sizeof(Exchange)))
    {
        close(fd);
        std::cerr << "Resize failed\n";
        return 1;
    }
    auto xch = static_cast<volatile Exchange*>(
                    mmap(0, sizeof(Exchange),
                         PROT_READ | PROT_WRITE, MAP_SHARED,
                         fd, 0));
    if(!xch)
    {
        std::cerr << "no mapping\n";
        return 1;
    }
    xch->x=23;
    while(1)
    {
        // Do I need to insert some sync instruction here?
        std::cout << xch->x << std::endl;
        xch->x++;
        msync((void*)(xch), sizeof(*xch), MS_SYNC);
        sleep(1);
    }
}

由于您已经将 msyncMS_SYNC 结合使用,因此不再需要进一步同步。

基本手册页部分:

msync() flushes changes made to the in-core copy of a file that was mapped into memory using mmap(2) back to the filesystem.


MS_SYNC: Requests an update and waits for it to complete.


对于阅读,也不需要更多的同步。使用 msync 将数据写回文件,标记文件页面 "dirty",并且在下一次读取时,mmap 机制(使用更新后的值)再次读取文件页面。


更多信息:

  • 在您的示例中,如果您的地图未与页面对齐,则可能无法创建 mmap。作为地图大小/长度,始终使用页面大小的倍数。