【问题标题】:Shared Memory between two processes after execexec 后两个进程之间的共享内存
【发布时间】:2026-01-23 03:10:01
【问题描述】:

家长:

shm_id = shmget(IPC_PRIVATE, (1 << 16), IPC_CREAT | IPC_EXCL | 0777);
setenv("SOME_ENV_VAR",stringof(shm_id);
if(fork()=0){
    execve(some_path,argv);
}

孩子:

int shm_id = atoi(getenv("SOME_ENV_VAR"));
int *shared_mem = (int*)shmat(shm_id,0,NULL);
if(!shared_mem)
  return;
shared_mem[0]++;

我想编辑孩子的共享内存。为什么这不起作用的任何原因?我在 Parent.Im 中通过 shmget 分配共享 mem 块。我将 shm_id 作为 env 变量让孩子在 fork 和 exec 之后读取它。

在孩子中,我正在读取正确的 shm_id,然后尝试通过 shmat 获取指向共享内存的指针。在我的代码中,我已经验证了 Parent 和 Child 中的 shm_id 是相同的......有什么想法吗?

【问题讨论】:

  • 我在两个代码示例的每一行都看到至少一个错误,但代码的基本轮廓是正确的,除了您需要在父级和孩子(fork之后执行此操作)。如果您需要更多帮助,请向我们提供完整的程序,我们可以自己编译和运行,并详细告诉我们您在运行它们时实际发生了什么,以及这与您的预期有何不同。
  • 注:新程序应使用shm_open 和朋友而不是shmget 和朋友。
  • shmat() 调用应该是 shmat(shm_id, NULL, 0)。
  • @gblaster,你完成这个任务了吗?请告诉我,除了函数调用参数混乱之外,您还有什么问题。谢谢

标签: c linux fork system-calls shared-memory


【解决方案1】:

shmgetkey_t 参数与该函数返回的标识符不同。用一个代替另一个是不明智的。

但是,如果您更改它并传达 shmid 而不是 key,您的基本方法将起作用。

shmid 是系统范围的全局标识符,如果您拥有适当的进程权限,shmat 将成功,即使您是不相关的进程。 (而且,即使您是相关的,execve 也会分离任何共享内存段,需要显式重新附加。)

请注意,规范对此并没有非常明确,说"[e]ach individual shared memory segment ... shall be identified by a unique positive integer, called ... a shared memory identifier, shmid."

【讨论】:

  • shmget 的返回值,假设调用成功,是一个“共享内存标识符”,正确传递给shmat。但是,我不清楚 POSIX/XSI 是否允许像 OP 那样跨进程边界对“共享内存标识符”进行序列化和反序列化。它没有说你可以,但也没有说你不能。
  • @zwol。孩子的 shmat 不会失败。它试图给我一个有效的指针...... Ofc 它与父级不同,因为我现在在子级中有一个新的进程地址空间,但我觉得这应该可以工作......
  • @gblaster 我支持我在评论您的问题时所说的一切,除了我现在不确定转移shmget 的返回值是否符合 100% 的犹太教规从一个过程到另一个过程。但如果shmat 在孩子身上没有失败,那似乎不太可能成为问题。
  • @zwol 在进一步阅读和测试后,我认为这是规范允许的。答案已编辑。
【解决方案2】:

在操作系统级别的段由 key 标识,ID 仅对进程是本地的。每个进程都需要执行一个 get(向它们传递相同的密钥)和一个 at 来使用内存。

这里有一个例子:http://www.csl.mtu.edu/cs4411.ck/www/NOTES/process/shm/shmat.html

【讨论】: