gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 21:00:21 24 4
gpt4 key购买 nike

我在共享内存方面遇到了问题。我有一个进程可以很好地创建和写入共享内存段。但是我无法获得第二个进程来附加相同的现有段。如果我使用 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 并对其进行硬编码在我的第二个过程中,第二个过程可以很好地附加到它。所以问题似乎是生成两个进程用来标识单个共享段的公共(public) ID。

我有几个问题:

(1) 是否有更简单的方法来获取现有共享内存段的 shmid?我必须将 三个 单独的参数从第一个进程(创建段)传递给第二个进程,这样第二个进程才能获得相同的共享段,这对我来说似乎很疯狂。我可以忍受必须传递 2 个参数:像“/dev/null”这样的文件名和相同的共享 ID(我的代码中的 nSharedMemoryID)。但是必须传递给 shmget() 例程以获取 shmid 的段的大小似乎毫无意义,因为我不知道实际分配了多少内存(由于页面大小问题)所以我不能当然是一样的。(2) 我在第二个过程中使用的段大小是否必须与在第一个过程中最初创建段所用的段大小相同?我试图将其指定为 0,但仍然出现错误。(3)同样,权限是否必须相同?也就是说,如果共享段是为用户/组/世界创建的读/写,第二个进程是否可以只对用户使用读? (两个进程的同一用户)。(4) 当文件“/dev/null”明显存在于两个进程时,为什么 shmget() 会因“没有这样的文件或目录”错误而失败?我假设第一个进程不会在该节点上放置某种锁,因为那是毫无意义的。

感谢任何人可以提供的帮助。我已经为此苦苦挣扎了几个小时——这意味着我可能正在做一些非常愚蠢的事情,当有人指出我的错误时,我最终会让自己感到尴尬:-)

谢谢,-安德烈斯

最佳答案

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

最终您可以评估使用 POSIX 兼容的 shm_open() 替代方案 - 应该更简单或至少更现代......

(2) 关于大小,重要的是指定的大小小于/等于现有段的大小,因此如果它四舍五入到下一个内存页面大小没有问题。仅当它更大时才会出现 EINVAL 错误。

(3) 模式标志仅在您第一次创建段时相关(大多数情况下是肯定的)。

(4) shmget() 因“没有这样的文件或目录”而失败的事实仅意味着它没有找到具有该 的段(现在很迂腐:不是 id - 我们通常通过 shmget() 引用 id 返回值,随后使用) - 你检查过 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

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

最后的问题是,在原始代码中,他稍后调用 shmctl() 告诉在附加其他进程之前,在最后一个进程分离它时分离该段。

问题在于,这实际上使段成为私有(private)的。它的键被 ipcs -m 标记为 0x00000000 并且不能再被其他进程附加 - 它实际上被标记为延迟删除。

关于c++ - 如何附加到现有的共享内存段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22262029/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com