C Posix共享内存初始化

C Posix共享内存初始化,c,linux,unix,posix,shared-memory,C,Linux,Unix,Posix,Shared Memory,我的问题是关于初始化通过使用shm\u open()和mmap()获得的内存。我在几个地方看到的一个常见建议是使用标志调用shm_open():如果成功,那么我们是共享内存的第一个用户,可以初始化它,否则我们不是第一个,共享内存已经被另一个进程初始化 然而,从我对shm_open的理解以及我在Linux上所做的测试来看,这是行不通的:即使在共享内存对象的最后一个用户取消映射并关闭之后,共享内存对象仍会留在系统中。使用O|u create | O|u EXCL调用shm_open,然后关闭描述符并

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

然而,从我对
shm_open
的理解以及我在Linux上所做的测试来看,这是行不通的:即使在共享内存对象的最后一个用户取消映射并关闭之后,共享内存对象仍会留在系统中。使用
O|u create | O|u EXCL
调用
shm_open
,然后关闭描述符并退出的简单测试程序将在第一次运行时成功,但在第二次运行时仍将失败,即使当时没有其他人使用共享内存

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

那么,关于使用
shm_open
O|u create | O_EXCL
的建议是错误的,还是我遗漏了什么

我知道可以使用
shm\u unlink()
删除共享内存对象,但这似乎只会导致更多问题:

  • 如果一个进程在调用
    shm\u unlink()
    之前死亡,那么我们回到上面描述的问题

  • 如果一个进程调用
    shm_unlink()
    ,而其他一些进程仍映射到同一共享内存中,那么这些其他进程仍将一如既往地继续使用它。现在,如果另一个进程来调用具有相同名称的
    shm_open()
    ,并指定了
    O_create
    ,它将实际成功地创建具有相同名称的新共享内存对象,这与其他进程仍在使用的旧共享内存对象完全无关。现在,我们有一个进程试图通过共享内存与其他进程通信,但完全没有意识到它使用了错误的通道


  • 我习惯于Windows语义,其中共享内存对象只有在至少一个句柄打开时才存在,因此Posix的内容非常混乱。

    由于您使用
    O_EXCL
    标志,我将假设您有一组进程聚集在一个主进程(段的创建者)周围

    然后,您的主进程将通过调用
    shm\u open
    创建共享内存段:

    shmid = shm_open("/insert/name/here", O_CREAT|O_EXCL, 0644);
    if (-1 == shmid) {
        printf("Oops ..\n");
    }
    
    在这里,从机已准备好使用该段。由于主机必须创建段,因此无需在从属调用中使用
    O_create
    标志。如果在尚未创建或已销毁段时执行从属调用,则只需处理可能的错误

    当您的任何进程对该段完成时,它应该调用
    shm\u unlink()
    。在这种体系结构中,主人通常是在喂奴隶。当它没什么可说的时候,它就闭嘴了。然后,从机有责任优雅地处理相应的错误

    如您所述,如果一个进程在调用
    shm\u unlink
    过程之前死亡,那么该段将在此后继续存在。为了避免在某些情况下出现这种情况,您可以定义自己的信号处理程序,以便在接收到诸如
    SIGINT
    之类的信号时执行该操作。无论如何,如果
    SIGKILL
    被发送到您的进程中,您将无法覆盖混乱

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

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

    您可以执行以下操作:
    int测试=shmget(键,大小,0);把它放在每个过程的起点。如果尚未创建现有共享内存,则此处的零标志尝试打开该内存。测试将等于-1,因此,如果测试-1转到并创建共享内存,则您可以在此语句后进行检查,否则您将获得现有共享内存的id。。。。。我希望这有助于

    看起来您在使用shm段时不会将其设置为删除。因此,它在您的过程中幸存下来。您可以在终端中使用
    ipcs
    命令来查看您的系统中当前有哪些类型的IPC内容(信号量、shm段等)。但是如何将其设置为删除?是否有要传递给shm_open()的标志?我在手册页上找不到任何内容。@Rerito:OP对您的评论有什么想法吗?在共享内存的实际用例中,可能共享同一段的两个进程将同时处于活动状态。那么,没有理由不在需要时调用
    shm_unlink()
    。因为我在回答中做了一些假设,您能给我们提供更多关于您使用共享内存的原因的信息吗?谢谢您的回复。然而,在我的例子中,进程不知道它是“主”还是“从”。这里的全部问题是找出它是哪一个。基本上,一旦进程映射到共享内存,它就需要回答“我是第一个吗?”的问题