5

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

但是,根据我shm_open对 Linux 的理解和测试,这是行不通的:共享内存对象会留在系统中,即使在共享内存对象的最后一个用户取消映射并关闭之后也是如此。一个简单的测试程序,它调用shm_openO_CREAT|O_EXCL然后关闭描述符并退出,将在第一次运行时成功,但在第二次运行时仍然会失败,即使当时没有其他人正在使用共享内存。

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

那么关于使用shm_openwith的建议O_CREAT|O_EXCL是错误的,还是我错过了什么?

我确实知道可以使用 删除共享内存对象shm_unlink(),但似乎只会导致更多问题:

  1. 如果一个进程在调用之前就死掉了,shm_unlink()那么我们又回到了上面描述的问题。

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

我习惯于 Windows 语义,其中共享内存对象仅在至少有一个句柄对其开放时才存在,所以这个 Posix 的东西非常令人困惑。

4

2 回答 2

2

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

然后,您的主进程将使用以下调用创建共享内存段shm_open

shmid = shm_open("/insert/name/here", O_CREAT|O_EXCL, 0644);
if (-1 == shmid) {
    printf("Oops ..\n");
}

在这里,从站已准备好使用该段。由于 master 必须创建段,因此无需O_CREAT在 slave 调用中使用 flag。如果在段尚未创建或已销毁时执行从属调用,您只需处理可能的错误。

当您的任何进程对段完成时,它应该调用shm_unlink(). 在这种架构中,主人通常是在喂奴隶。当它无话可说时,它就闭嘴了。然后,从站有责任优雅地处理相应的错误。

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

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

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

于 2013-10-25T15:09:24.060 回答
0

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

于 2014-05-11T00:12:30.423 回答