当进程使用 shm_open() 时,Linux 内核如何分配内存指针?

Posted

技术标签:

【中文标题】当进程使用 shm_open() 时,Linux 内核如何分配内存指针?【英文标题】:How does Linux Kernel assigns memory pointers when a process uses shm_open()? 【发布时间】:2011-02-23 11:18:59 【问题描述】:

我使用的是 Linux 2.6,但遇到了一个奇怪的问题。我有 3 个并发进程(从同一个进程派生)需要获取 3 个不同的共享内存段,每个进程一个。每个进程都执行这段代码(请注意'message'类型是用户定义的)

    message *m;
    int fd = shm_open("message", O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
    ftruncate(fd, sizeof(message));
    m = mmap(NULL, sizeof(message), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    char messagename[16];
    snprintf(messagename, sizeof(messagename), "%p", m);
    char path[32] = "/dev/shm/";
    strcat(path, messagename);
    rename("/dev/shm/message", path);

让我解释一下:我希望每个进程分配一个包含消息的共享内存区域。为了确保另一个进程(消息接收者)可以访问同一个 shm,然后我将我的 shm 文件从“message”重命名为以消息指针命名的字符串(这是因为接收消息的进程已经知道指针)。

但是,在执行程序时,我尝试打印(出于调试目的)每个进程在映射使用 shm_open 获得的 fd 时收到的指针,我注意到它们都得到了相同的指针。这怎么可能?我认为也许其他进程在第一个进程之后和重命名段之前执行了 shm_open(),所以我也尝试通过使用进程共享互斥体使这些代码行成为原子操作,但问题仍然存在。

非常感谢任何形式的帮助或建议。

【问题讨论】:

【参考方案1】:

您的进程在分叉时都以相同的地址空间布局开始,然后遵循非常相似的代码路径。因此,它们最终都具有相同的 m 值也就不足为奇了。

但是,一旦它们成为独立的进程,它们的地址空间就会变得独立,因此具有相同的 m 并不意味着所有 ms 都指向同一个东西.

此外,我不确定您在创建共享内存块后重命名/dev/shm 条目的想法是否安全或可移植。如果你希望每个进程的共享内存块有一个唯一的名称,为什么不将名称基于进程ID(保证在给定时间点唯一)并将其直接传递给shm_open,而不是去麻烦以后改名吗?

【讨论】:

谢谢,您使用 pid 的想法似乎不错,我一定会试一试。但是,通过 shm_open() 我询问了一个共享(而不是私有)内存指针,并且我每次都期待一个不同的指针,而不管进程的虚拟内存空间如何,我认为这与共享内存无关.此外,即使我为进程调用的每个 shm_open() 使用不同的名称,它们都得到相同的地址。如果 shm_open() + mmap() 给出了一个共享内存指针,如果 shm 的名字不同,它们怎么可能都一样呢? 从一个进程对内存的所有访问都通过该进程的虚拟地址空间。底层内存可能是共享的,但每个应用程序对它的看法是私有的。所以它可能出现在每个进程中的相同地址,或者不同进程中的不同地址,完全由操作系统决定。 ... 或者相反,不同的共享内存块可能会出现在不同进程中的同一地址,这就是发生在你身上的事情。【参考方案2】:

不同进程中的相同虚拟地址可以(并且通常会)映射到内存中的不同物理页面。您可能想阅读the wikipedia article on virtual memory。

【讨论】:

谢谢!我已经知道虚拟内存。不过,我在想,即使进程具有不同的内存空间,使用 shm_open() 和 mmap() 也会返回指向某些共享区域的指针,这些共享区域每次都应该是“唯一的”。【参考方案3】:

我通过在分叉前创建 mmap 解决了类似的问题。因此,在分叉后,所有进程之间共享相同的区域。然后我把我的信号量和互斥锁放在定义的位置上。效果很好。

【讨论】:

以上是关于当进程使用 shm_open() 时,Linux 内核如何分配内存指针?的主要内容,如果未能解决你的问题,请参考以下文章

linux进程间通信之Posix共享内存用法详解及代码举例

为啥使用 shm_open?

我们在哪里调用“Shm_unlink()”

已使用 -L /lib -lrt -lpthread 未定义对“shm_open”的引用

linux系统内存达多少会杀掉进程

Linux如何获取进程在物理内存中的所有内容?当进程在内存中的内容发生变化时,又如何获知?内核中实现