Posix共享内存初始化

时间:2013-10-19 08:33:38

标签: c linux unix posix shared-memory

我的问题是关于初始化使用shm_open()mmap()获得的内存。我在几个地方看到的一个常见建议是使用标志shm_open()调用O_CREAT|O_EXCL:如果成功,那么我们是共享内存的第一个用户并且可以初始化它,否则我们不是第一个和共享内存已经被另一个进程初始化。

但是,根据我对shm_open的理解和我在Linux上所做的测试,这不起作用:共享内存对象在系统中遗留下来,即使在共享的最后一个用户之后也是如此内存对象已取消映射和关闭。一个简单的测试程序调用{​​{1}}和shm_open,然后关闭描述符并退出,将在第一次运行时成功,但在第二次运行时仍会失败,即使其他人没有使用共享内存那个时候。

在我看来(至少在我测试的系统上)O_CREAT|O_EXCL的行为与shm_open几乎相同:如果我修改我的简单测试程序来写一些内容到共享内存(通过open()获得的指针)并退出,然后共享内存对象将持久保存其内容(我可以运行另一个简单的程序来回读我之前写的数据)。

关于使用mmapshm_open错误使用的建议,还是我错过了什么?

我知道可以使用O_CREAT|O_EXCL删除共享内存对象,但似乎只会导致更多问题:

  1. 如果某个流程在调用shm_unlink()之前就已消失,那么我们就会回到上述问题。

  2. 如果一个进程调用shm_unlink()而其他一些进程仍然映射到同一个共享内存,则这些其他进程仍将像往常一样继续使用它。现在,如果另一个进程调用shm_unlink()并且指定了shm_open(),它实际上将成功创建具有相同名称的新共享内存对象,这与旧的共享内存对象完全无关其他进程仍在使用。现在我们有一个进程尝试通过共享内存与其他进程通信,并且完全没有意识到它使用了错误的通道。

  3. 我习惯于Windows语义,只要至少有一个句柄对它开放,共享内存对象就存在,所以这个Posix的东西很混乱。

2 个答案:

答案 0 :(得分:2)

由于您使用O_EXCL标志,我将假设您有一组围绕一个主人(该段的创建者)收集的进程。

然后,您的主进程将使用shm_open

调用创建共享内存段
shmid = shm_open("/insert/name/here", O_CREAT|O_EXCL, 0644);
if (-1 == shmid) {
    printf("Oops ..\n");
}

此处,从属设备已准备好使用该段。由于主HAS要创建段,因此不需要在从站调用中使用O_CREAT标志。如果在尚未创建或已经销毁段的情况下执行从属调用,则只需处理可能的错误。

如果您的任何流程完成了细分,则应调用shm_unlink()。在这种体系结构中, master 通常为 slave 提供服务。当它没有什么可说的时候,它就会关闭。然后奴隶有责任优雅地处理相应的错误。

如您所述,如果某个进程在调用shm_unlink过程之前死亡,那么该分段将继续存在。为了在某​​些情况下避免这种情况,您可以定义自己的信号处理程序,以便在收到SIGINT等信号时执行操作。无论如何,如果SIGKILL被发送到您的流程,您将无法弥补这些混乱。

编辑: 更具体地说,O_CREAT | O_EXCL的使用在不必要时是错误的。通过上面的小例子,您可以看到master需要创建段,因此需要这些标志。另一方面,任何从属进程都不必创建它。因此,您绝对禁止在相关电话中使用O_CREAT

现在,如果另一个进程在已创建段时调用shm_open(..., O_CREAT, ...),它将只检索与此段相关的文件描述符。因此它将在正确的渠道上(如果它有权这样做,请参阅mode参数)

答案 1 :(得分:0)

您可以执行以下操作: int test = shmget(key_t key,size,0);把它放在每个过程的明星。零标志在这里试图打开一个现有的共享内存,如果它尚未创建测试将等于-1所以你可以在这个语句之后检查如果test -1去创建一个共享内存,否则你只有一个现有共享内存的id .....我希望这个帮助