【问题标题】:shared memory is not shared between processes共享内存不在进程之间共享
【发布时间】:2025-06-06 04:30:02
【问题描述】:

我正在编写一个服务器程序,它从客户端接收消息并将消息广播到所有以前的客户端。我需要在进程之间创建共享内存,但是共享内存似乎不起作用。

这是我的代码:

 int shmid2; key_t key2; void* shm2;
 string name_list;
 key2=ftok("tmp",'d');
 //create
 if ((shmid2 = shmget ( key2, sizeof(char)*1000, IPC_CREAT | 0666)) < 0) {
         perror("shmget2");
         exit(1);}
 //attach
 shm2 = shmat(shmid2, (void *)0, 0) ;
 name_list= (char*) shm2;
 if ( shm2 == (char *) -1) {
        perror("shmat2");
        exit(1);}
 ... do other things...
  switch (pid=fork()){
  case -1:
  { perror("ERROR on fork");
  break;}
  case 0://children
  { 
  ...modify name_list by getting message and append message to name_list..
  name_list.append(message);
  break;}
  default://parent
  close(connection);
  }

当我在children进程中修改name_list时,其他进程似乎看不到这个修改。 任何人都可以提出任何建议吗?谢谢!!

更新:我尝试按照建议进行更改,但仍然无法正常工作。

name_list = (char*) shmat(shmid2, (void *)0, 0) ;

任何人都可以帮助我吗?非常感谢!

【问题讨论】:

  • 1:请修复缩进,您的代码很难阅读。 2:你是如何“修改name_list”的?修改它指向的内存,还是修改变量?顺便说一句,请包括变量声明
  • 已修复。你知道为什么这不起作用吗?

标签: c++ network-programming fork shared-memory


【解决方案1】:

当您将std::string 对象name_list 分配给您从共享内存中获得的指针时:

string name_list;
// ...
shm2 = shmat(shmid2, (void *)0, 0) ;
name_list= (char*) shm2;
// ...
name_list.append(message);

你正在调用字符串的赋值运算符,它复制它被赋予到新内存中的指针。当您的代码操作name_list 时,它正在操作副本,而共享内存保持不变。

看起来您正试图从一个进程写入共享内存,并在另一个进程中读取它,这不是一个容易解决的问题。弄清楚哪个进程可以读取和写入哪些内存是很棘手的,保持高速缓存的一致性也是如此。查找生产者-消费者循环环形缓冲区(在 Google 上或在 Stack Overflow 上)以了解此问题的一些标准解决方案。

要回答您最初的问题,一旦您在本地内存中操作了字符串,您需要将其放回共享内存中。这将在紧要关头完成:

if(name_list.size() <= 1000) {
    memcpy(shm2, name_list.data(), name_list.size());
} else {
    // error: name list overflowed shared memory
}

您也可以直接操作共享内存,使用指针shm2,直接使用 C 指针,注意不要溢出您的 1000 字节缓冲区。

【讨论】:

  • 您好,Commodore,您的回答似乎接近解决方案。如果我在这里很愚蠢,请原谅,但我仍然不明白为什么我要保持共享内存不变。你能更详细地解释一下吗?谢谢!!
  • 我也是这么想的。 @Qii:name_list= (char*) shm2; 创建一个字符串。在字符串构造函数中,它复制数据。因此,当您更改 name_list 时,它正在更改与您构造对象方式的 char* 无关的变量(再次因为它被复制)。为了让事情变得更简单,我建议不要使用对象并使用原始数据(整数、字符、浮点数和数组以及简单的结构)
  • 感谢 Commodore 和 acidzombie24!我花了几个小时试图找出问题所在。现在这是一个很大的解脱。
  • 大家好,坏消息,我按照建议尝试了 name_list = (char*) shmat(shmid2, (void *)0, 0),但仍然无法正常工作..
【解决方案2】:

总结一下: 如果您使用字符串类,您将始终操作共享内存的副本。

两种解决方案: 1.不要使用字符串,而是使用标准的C方法直接操作char数组(例如strcat来追加字符) 2. 修改完name_list后,将其复制回共享内存。

版本 1 更快。版本 2 更简单。

【讨论】: