mmap是否与所有进程共享内存?

时间:2012-07-31 11:05:15

标签: c linux operating-system shared-memory mmap

当我这样做时:

myProgram.h
myProgram.c

    struct PipeShm
    {
    // all my fields
    // more 
    // ...

    };



    struct PipeShm myPipe = { /* initialization for all fields */ };
    struct PipeShm * sharedPipe = &myPipe;

void func()
{
 sharedPipe = mmap (NULL, sizeof * sharedPipe, PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS, -1, 0);

}

当我mmap指针sharedPipe时,如果我从main()调用来自myProgram代码的任何方法,那么所有进程都会共享与我共享的确切共享内存{ {1}}结构?

或者每个新创建的孩子都会拥有自己的新myPipe

此致

修改

这是在我阅读了评论&答案:现在进行了更改,我只在分配后才初始化段的值:

myPipe

问题仍然存在,共享内存似乎不是在进程之间共享,因为在运行和分叉主要时:

#include "my_pipe.h"

struct PipeShm * sharedPipe = NULL;



int shm_pipe_init()
{
    if (!sharedPipe)
    {
        int myFd = shm_open ("/myregion", O_CREAT | O_TRUNC | O_RDWR, 0600);

        if (myFd == -1)
            error_out ("shm_open");

        // Allocate some memory in the region - We use ftruncate, write(2) would work just as well
        int retAlloc = ftruncate (myFd, sizeof * sharedPipe);
        if (retAlloc < 0)
            error_out("ftruncate");


        sharedPipe = mmap (NULL, sizeof * sharedPipe,
                PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS, myFd, 0);

        if (!sem_init (&sharedPipe->semaphore, 1, 0))
        {
            sharedPipe->init = TRUE;
            sharedPipe->flag = FALSE;
            sharedPipe->ptr1 = NULL;
            sharedPipe->ptr2 = NULL;
            sharedPipe->status1 = -10;
            sharedPipe->status2 = -10;
            sharedPipe->semaphoreFlag = FALSE;
            sharedPipe->currentPipeIndex = 0;

        }
        else
            perror ("shm_pipe_init");
    }
    return 1;   // always successful
}

我仍然得到输出,模拟只有一个进程正在运行的行为(而不是多个输出,我只得到一个一个一对,取决于过程之间的竞争条件)。

3 个答案:

答案 0 :(得分:5)

如果您打算多次调用此程序,答案是“否”。如果您打算在创建映射后进行分叉,则答案为“是”。

匿名映射没有底层文件。因此,创建匿名映射的进程无法指定特别需要哪个已存在的映射(这也不是预期的用法,您应该获得一个新的独立映射)。因此对第一种情况“不”。

共享映射允许拥有相同映射的所有进程访问相同的phsyical内存。这意味着,如果您在创建映射后fork,那么fork将主要以通常的方式工作,将该流程拥有的所有页面标记为写入时复制,除非映射中的页面。父节点和子节点都将保留映射页面,并且能够通过指针访问相同的物理内存(这意味着页面甚至会具有相同的虚拟地址 - 这通常不是映射文件时可以依赖的东西,但在这种情况下,操作系统别无选择,只能确保是这种情况。)

关于匿名和共享映射的组合或者究竟应该发生什么,联机帮助页仍然含糊不清,但TLPI第49.7章明确提到了MAP_SHARED|MAP_ANONYMOUS

  

[...]然后调用fork(),然后,因为fork()生成的子进程继承映射,两个进程共享内存区域。

因此第二种情况为“是”。

Re:已编辑的帖子
订单错误:

fork();
shm_pipe_init();

此分支优先,然后初始化共享内存。这将只创建一个共享(读作共享 - ,它可以在将来共享,如果进程再次分叉,但它不会神奇地与父级共享!)映射分别为每个流程

然后你有两个映射,每个进程一个映射,它们将由它们各自的子进程和孙进程(如果有的话)共享,但这对于实现你想要的东西没什么帮助。它们“共享”的事实并不重要,它们是不同的映射,并且对于其他各个过程都是未知的。

首先创建映射,然后 fork。这将创建一个共享映射,这两个进程确实拥有/共享并可用于预期目的。

(此外,你对fork的使用并没有严格错误,但有点奇怪...你通常应该检查返回值,所以你知道哪一个是父,哪一个是并不是fork不能失败。当然,如果这根本不重要,因为父母和孩子总是100%完全相同,而你不关心失败,那很好。通常,一个但通常想知道。)

答案 1 :(得分:2)

每个都有自己的,因为指针 sharedPipe的更改 不会影响myPipe

答案 2 :(得分:2)

让我们逐步完成你在这里做的事情

struct PipeShm myPipe = { /* initialization for all fields */ };

这会将PipeShm结构分配为全局变量

struct PipeShm * sharedPipe = &myPipe;

这将创建一个指向先前创建的结构的指针。

现在你要将指针sharedPipe修改为mmap返回的内容(可能是共享内存区域的地址)而不是之前分配的结构(注意:{{1}仍然存在 - 只是没有指出)。

myPipe

据我所见,您还没有尝试访问sharedPipe = mmap (NULL, sizeof * sharedPipe, PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS, -1, 0); 。所以现在,你基本上有一个全局变量一部分共享内存(两者都显示为未使用过)。

这是我不太确定你要做什么的地方。

如果要访问共享内存,则需要在sharedPipe返回后取消引用sharedPipe指针(如果是,全局变量的重点是什么?)。 / p>

如果您想访问全局变量,只需将其作为mmap访问(如果是,myPipe是什么?)。

如果你想同时访问这两者,那么使用上述的组合(如果是,那么做什么mmap?)