如何附加到现有的共享内存段

我遇到了共享内存的问题。 我有一个创build和写入共享内存段的过程就好了。 但是我无法获得第二个过程来附加相同的现有细分。 我的第二个进程可以创build一个新的共享段,如果我使用IPC_CREATE标志,但我需要附加到由第一个进程创build的现有共享段。

这是我在第二个过程中的代码:

int nSharedMemoryID = 10; key_t tKey = ftok("/dev/null", nSharedMemoryID); if (tKey == -1) { std::cerr << "ERROR: ftok(id: " << nSharedMemoryID << ") failed, " << strerror(errno) << std::endl; exit(3); } std::cout << "ftok() successful " << std::endl; size_t nSharedMemorySize = 10000; int id = shmget(tKey, nSharedMemorySize, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (id == -1) { std::cerr << "ERROR: shmget() failed, " << strerror(errno) << std::endl << std::endl; exit(4); } std::cout << "shmget() successful, id: " << id << std::endl; unsigned char *pBaseSM = (unsigned char *)shmat(id, (const void *)NULL, SHM_RDONLY); if (pBaseSM == (unsigned char *)-1) { std::cerr << "ERROR: shmat() failed, " << strerror(errno) << std::endl << std::endl; exit(5); } std::cout << "shmat() successful " << std::endl; 

问题是第二个进程总是错误的调用shmget()与“没有这样的文件或目录”错误。 但是,这是我在第一个过程中使用的完全相同的代码,它在那里工作得很好。 在创build共享段的第一个进程中,我可以写入内存段,我可以用“ipcs -m”看到它。另外,如果从段的“ipcs -m”命令中得到shmid并且硬编码在我的第二个进程和第二个进程可以附加到它就好了。 所以这个问题似乎是两个stream程用来识别单个共享段的共同标识的产生。

我有几个问题:

(1)是否有更简单的方法来获得现有的共享内存段的shmid? 我似乎很疯狂,我必须从第一个进程(创build该段)传递三个独立的参数到第二个进程,这样第二个进程才能获得相同的共享段。 我可以生活在必须传递两个参数:文件名像“/ dev / null”和相同的共享ID(在我的代码中的nSharedMemoryID)。 但是为了得到shmid必须传递给shmget()例程的段的大小似乎没有意义,因为我不知道究竟分配了多less内存(因为页面大小的问题),所以我不能肯定是一样的。 (2)我在第二个过程中使用的段大小是否与第一个过程中用于初始创build段的段的大小相同? 我试图把它指定为0,但我仍然得到错误。 (3)同样,权限必须相同吗? 也就是说,如果共享段是为用户/组/世界创build的,则第二个进程是否可以为用户使用? (两个进程的用户相同)。 (4),当两个进程明显存在文件“/ dev / null”时,为什么shmget()失败,出现“No such file or directory”错误? 我假设第一个进程没有在该节点上设置某种locking,因为这样做毫无意义。

感谢任何人可以给的帮助。 我一直在挣扎几个小时 – 这意味着我可能做一些非常愚蠢的事情,当有人指出我的错误时,最终会让自己难堪.-)

谢谢,安德烈

Solutions Collecting From Web of "如何附加到现有的共享内存段"

(1)作为一个不同的方式:附加过程扫描用户的现有部分,试图附加所需的大小,检查段的开始“魔术字节序列”(排除同一用户的其他程序)。 或者,您可以检查附加的过程是否是您期望的过程。 如果其中一个步骤失败了,这是第一个步骤,将创建该部分…麻烦的是,我看到它在70年代的代码。

最终,您可以评估使用符合POSIX的shm_open()替代方案 – 应该更简单或至少更现代化…

(2)关于大小,指定的大小小于或等于现有段的大小是很重要的,所以如果四舍五入到下一个内存页大小,则不存在问题。 只有在较大的情况下才会出现EINVAL错误。

(3)模式标志仅在您第一次创建分段时(大部分确定)才相关。

(4) shmget()失败与“没有这样的文件或目录”的事实意味着只有它没有找到与该关键字的段(现在是迂回:不ID – 与ID我们通常引用的值shmget() ,随后使用) – 你检查了tKey是一样的吗? 你的代码在我的系统上工作正常。 只是在它周围添加了一个main()。

编辑:附加工作程序

 #include <iostream> #include <sys/ipc.h> #include <sys/shm.h> #include <errno.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> int main(int argc, char **argv) { int nSharedMemoryID = 10; if (argc > 1) { nSharedMemoryID = atoi(argv[1]); } key_t tKey = ftok("/dev/null", nSharedMemoryID); if (tKey == -1) { std::cerr << "ERROR: ftok(id: " << nSharedMemoryID << ") failed, " << strerror(errno) << std::endl; exit(3); } std::cout << "ftok() successful. key = " << tKey << std::endl; size_t nSharedMemorySize = 10000; int id = shmget(tKey, nSharedMemorySize, 0); if (id == -1) { std::cerr << "ERROR: shmget() failed (WILL TRY TO CREATE IT NEW), " << strerror(errno) << std::endl << std::endl; id = shmget(tKey, nSharedMemorySize, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | IPC_CREAT); if (id == -1) { std::cerr << "ERROR: shmget() failed, " << strerror(errno) << std::endl << std::endl; exit(4); } } std::cout << "shmget() successful, id: " << id << std::endl; unsigned char *pBaseSM = (unsigned char *)shmat(id, (const void *)NULL, SHM_RDONLY); if (pBaseSM == (unsigned char *)-1) { std::cerr << "ERROR: shmat() failed, " << strerror(errno) << std::endl << std::endl; exit(5); } std::cout << "shmat() successful " << std::endl; } 

编辑:输出

 $ ./a.out 33 ftok() successful. key = 553976853 ERROR: shmget() failed (WILL TRY TO CREATE IT NEW), No such file or directory shmget() successful, id: 20381699 shmat() successful $ ./a.out 33 ftok() successful. key = 553976853 shmget() successful, id: 20381699 shmat() successful 

解决方案 – 在聊天后(哇,有聊天!)讨论:

最后,问题是在最初的代码中,他之后调用shmctl()来告诉在另一个进程被连接之前,将最后一个进程分离出来。

问题是,这实际上使该部分隐私。 它的关键是被ipcs -m标记为0x00000000,不能被其他进程连接 – 实际上标记为延迟删除。

我只是想发布Sigismondo给我的所有帮助的结果,并将解决方案发布到这个问题上,以防其他人有同样的问题。

线索是使用“ipcs -m”,并注意到键值为0,这意味着共享段是私有的,所以第二个进程无法附加到它。

另外一个怪癖是:我打电话给以下人:

int nReturnCode = shmctl(id,IPC_RMID,&m_stCtrlStruct);

我的意图是设置该段的模式,以便在所有正在使用它的进程退出时删除它。 但是,这个调用有一个副作用,即使它是在不使用IPC_EXCL标志的情况下创建的。

希望这可以帮助其他人解决这个问题。

而且,非常感谢Sigismondo花时间帮助我 – 我从我们的聊天中学到了很多东西!

-Andres