Yev*_*y P 5 c unix linux posix shared-memory
我的问题是关于初始化使用shm_open()和获得的内存mmap()。我在几个地方看到的一个常见建议是shm_open()使用标志调用O_CREAT|O_EXCL:如果成功,则我们是共享内存的第一个用户并可以对其进行初始化,否则我们不是第一个用户,并且共享内存已被另一个进程初始化。
但是,根据我的了解shm_open以及在Linux上进行的测试,这是行不通的:即使在共享内存对象的最后一个用户未映射并关闭后,共享内存对象仍留在系统中。一个简单的测试程序,它要求shm_open有O_CREAT|O_EXCL,然后关闭描述符和退出,将在第一次运行成功,但仍然会失败的第二次运行,即使没有其他人使用当时的共享内存。
在我看来,实际上(至少在我测试的系统上)的行为与以下行为shm_open几乎完全相同open():如果我修改我的简单测试程序以将某些内容写入共享内存(通过通过获取的指针mmap)并退出,则共享内存对象将永久保留其内容(我可以运行另一个简单程序以读取我先前编写的数据)。
那么,如何使用的意见shm_open与O_CREAT|O_EXCL刚才错了,还是我失去了一些东西?
我确实知道可以使用删除共享内存对象shm_unlink(),但似乎只会引起更多问题:
如果进程在调用之前死亡,shm_unlink()那么我们将回到上述问题。
如果一个进程调用shm_unlink()而其他进程仍映射到同一共享内存中,则这些其他进程仍将照常继续使用它。现在,如果另一个进程来shm_open()使用相同的名称并O_CREAT指定了名称,则它实际上将成功创建具有相同名称的新共享内存对象,这与其他进程仍在使用的旧共享内存对象完全无关。现在,我们有一个进程试图通过共享内存与其他进程进行通信,而完全不知道它使用了错误的通道。
我习惯了Windows语义,即只有打开了至少一个句柄,共享内存对象才会存在,因此Posix的内容非常令人困惑。
由于您使用该O_EXCL标志,我将假设您有一组围绕一个主机(段的创建者)聚集的进程。
然后,您的主进程将使用以下调用创建共享内存段shm_open:
shmid = shm_open("/insert/name/here", O_CREAT|O_EXCL, 0644);
if (-1 == shmid) {
printf("Oops ..\n");
}
Run Code Online (Sandbox Code Playgroud)
在这里,从站已准备好使用该段。由于主设备必须创建段,因此无需O_CREAT在从设备调用中使用该标志。如果在段尚未创建或已销毁时执行从属调用,您只需处理可能的错误。
当您的任何进程完成该段时,它应该调用shm_unlink(). 在这种架构中,主人通常会喂养奴隶。当它无话可说时,它就会闭嘴。然后从站有责任优雅地处理相应的错误。
正如您所说,如果进程在调用过程之前shm_unlink终止,则该段此后将继续存在。为了在某些情况下避免这种情况,您可以定义自己的信号处理程序,以便在SIGINT收到诸如此类的信号时执行操作。SIGKILL无论如何,如果发送到您的流程,您将无法掩盖混乱。
O_CREAT | O_EXCL编辑:更具体地说,不必要时使用是错误的。通过上面的小例子,您可以看到主设备需要创建段,因此需要这些标志。另一方面,任何从属进程都不必创建它。O_CREAT因此,您将绝对禁止在相关调用中使用。
现在,如果另一个进程shm_open(..., O_CREAT, ...)在该段已创建时调用,它将仅检索与该段相关的文件描述符。因此它将处于正确的渠道(如果它有权这样做,请参阅论点mode)