系统相关
首页 > 系统相关> > c-如何附加到现有的共享内存段

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

作者:互联网

共享内存出现问题.我有一个可以创建并写入共享内存段的进程.但是我无法再进行附加相同的现有细分的过程.如果我使用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)有没有更简单的方法来获取现有共享内存段的阴影?我觉得很疯狂,我必须将第一个流程(创建细分)的三个单独的参数传递给第二个流程,这样第二个流程才能获得相同的共享细分.我可以忍受必须传递2个参数:文件名(如“ / dev / null”)和相同的共享ID(我的代码中为nSharedMemoryID).但是必须传递给shmget()例程以获取shmid的段的大小似乎没有意义,因为我不知道确切分配了多少内存(由于页面大小问题),所以我无法肯定是一样的.
(2)我在第二个流程中使用的段大小是否必须与在第一个流程中最初创建该段的段的大小相同?我尝试将其指定为0,但仍然收到错误.
(3)同样,权限必须相同吗?也就是说,如果共享段是通过对用户/组/世界进行读/写创建的,那么第二个进程是否可以仅对用户使用读? (两个进程的用户相同).
(4)当两个进程明显都存在文件“ / dev / null”时,为什么shmget()失败并显示“没有这样的文件或目录”错误?我假设第一个进程不会对该节点施加某种锁,因为那将是毫无意义的.

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

谢谢,
-安德烈斯

解决方法:

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

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

(2)关于大小,重要的是指定的大小应小于/等于现有段的大小,因此,如果四舍五入到下一个内存页面大小就没有问题.您只会在EINVAL错误较大时得到它.

(3)模式标记仅在您首次创建分段时才相关(大多数情况下是确定的).

(4)shmget()失败并显示“没有这样的文件或目录”的事实仅意味着它没有找到具有该键的段(现在是pedantic:not id-使用id时,我们通常通过以下方式返回值returnet) 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,并且其他进程无法再附加它-实际上已将其标记为延迟删除.

标签:posix,shared-memory,linux,c-4,ipc
来源: https://codeday.me/bug/20191029/1962726.html