当前位置: 首页 > 知识库问答 >
问题:

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

马梓
2023-03-14

我在共享记忆方面遇到了麻烦。我有一个进程可以创建和写入共享内存段。但我无法获得第二个进程来附加相同的现有段。如果我使用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;

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

谢谢-安德烈斯

共有1个答案

刘焱
2023-03-14

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

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

(2)关于大小,重要的是指定的大小小于/等于现有段的大小,所以如果将其舍入到下一个内存页大小就没有问题了。只有当EINVAL误差较大时,才会得到它。

(4)shmget()以“no such file or directory”失败的事实仅仅意味着它没有找到具有该键的段(现在很迂腐:not id--使用id我们通常引用shmget()的值returnet,随后使用)--您是否检查过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 

问题是,这实际上使段私有。它的键被ipcs-m标记为0x00000000,并且不能再被其他进程附加--它实际上被标记为惰性删除。

 类似资料:
  • 问题内容: 如何确定将什么进程附加到共享内存段? 即我如何确定shmid 98306附加了哪些两个进程? 问题答案: 我认为您无法使用标准工具来做到这一点。您可以使用获取要附加/分离的 最后一个 进程的进程ID,但是我不知道如何使用来获取 所有 附加的进程。 对于两个进程相连的段,假设它们都 保持 相连,则可以从创建者PID 和最后一个相连的PID中找出这两个进程,但是它们不能扩展到两个以上进程,

  • 通过查看shmget()的手动页面,我了解到shmget()调用在内存中分配了#个页面,这些页面可以在进程之间共享。 它是否要创建内核内存页,并将其映射到进程的本地地址空间?还是为该段保留了相同的进程内存页,并将为其他附加进程共享相同的内存页? 调用shmget()时,内核将保留一定数量的段/页。 调用shmat()时,保留的段映射到进程的地址空间/页。 当一个新进程附加到同一段时,前面创建的内核

  • 共享内存是两个或多个进程共享的内存。 但是,为什么我们需要共享内存或其他通信方式呢? 重申一下,每个进程都有自己的地址空间,如果任何进程想要将自己的地址空间的某些信息与其他进程进行通信,那么只能通过IPC(进程间通信)技术进行。 我们已经知道,通信可以在相关或不相关的进程之间进行。 通常,使用管道或命名管道来执行相互关联的进程通信。 可以使用命名管道或通过共享内存和消息队列的常用IPC技术执行无关

  • 文档中一些特征序列,会有如下特性: 共享 附加作用: Driver Signal ControlEvent ... 不共享 附加作用: Single Completable Maybe ... 那什么是共享 附加作用,什么是不共享 附加作用? 共享 附加作用: ... let observable: Observable<Teacher> = API.teacher(teacherId: 1) l

  • 问题内容: 我对ES官方文档中的以下配额有一个疑问: 如果服务器具有80G内存,则发出以下命令以启动ES节点: 这意味着我只给ES进程提供最大30g内存。Lucene如何使用剩余的50G,因为Lucene在ES流程中运行,所以这只是流程的一部分。 问题答案: 该参数仅指示您为ES Java进程分配了多少 堆 。但是,将RAM分配给堆并不是使用服务器上可用内存的唯一方法。 Lucene确实在ES进程

  • 问题内容: 至于现在,我将在尝试附加对象时得到提示。我已经在互联网上搜索了一种解决方法。到目前为止,我发现的答案是无法完成。解决此问题的一种方法是将对象写入列表,然后将列表写入文件。 但是,每次添加新对象时,我都必须覆盖该文件。这似乎不是加班的最佳解决方案。 有没有一种方法可以将对象追加到现有对象流? 问题答案: 实际上,这很容易做到。当您添加到现有流时,需要使用ObjectOutStream的子