我在使用共享内存时遇到了问题。我有一个进程可以创建并成功地写入到一个共享内存段中。但是我无法让第二个进程附加到同一个现有段。如果我使用IPC_CREATE标志,我的第二个进程可以创建一个新的共享段,但我需要附加到第一个进程创建的现有共享段。
以下是我在第二个进程中的代码:
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()时总是出现“没有这样的文件或目录”错误。但这正是我在第一个进程中使用的相同代码,在那里它能够很好地工作。在创建共享段的第一个进程中,我可以写入内存段,我可以用“ipcs -m”看到它。 同时,如果我从ipcs -m命令中获取了片段的shmid,并在我的第二个进程中硬编码它,那么第二个进程就可以顺利地附加到它上面。因此,问题似乎在于两个进程都用来识别单个共享段的公共ID的生成。
我有几个问题:
(1)是否有更简单的方法来获取现有共享内存段的shmid?对我而言,我必须从第一个进程(创建该段)传递三个不同的参数给第二个进程,以便第二个进程可以得到相同的共享段。我可以接受需要传递2个参数:像“/dev/null”这样的文件名和相同的共享id(在我的代码中为nSharedMemoryID)。但是必须传递到shmget()例程中的段大小似乎是毫无意义的,因为由于页面大小问题,我不知道实际分配了多少内存,因此我不能确定它是相同的。
(2)我在第二个进程中使用的段大小是否必须与最初在第一个进程中创建该段时使用的段大小相同?我尝试将其指定为0,但仍然出现错误。
(3)同样,权限必须相同吗?也就是说,如果共享段是以用户/组/全局的读取/写入方式创建的,那么第二个进程只能使用用户的读取权限吗?(两个进程使用相同的用户)
(4)shmget()为什么在文件“/dev/null”对于两个进程显然存在时失败并出现“没有这样的文件或目录”错误?我假设第一个进程没有对该节点进行某种锁定,因为那将是无意义的。
感谢任何人能够给予的帮助。我已经为此挣扎了数小时 - 这意味着我可能做了一些真正愚蠢的事情,并且当有人指出我的错误时最终会使自己感到尴尬。
shmget
时,它应该将大小指定为0。这样就消除了你的一个抱怨。页面大小等与此无关。这对这些目的来说应该是不相关的。权限类似于文件权限。仅因为您为用户创建了具有r/w的文件并不意味着该用户必须在每个pgm中以r/w打开它。您可以选择只读或只写方式打开它。权限给予您许可,而不是提出要求。 - Duckftok
,您是否使用调试器或 printf 查看了返回的 key_t?我认为它只是在 typedef 后面的一个 int。 - Duck