exec()之后共享内存

问题描述 投票:0回答:2

如果子进程运行了 exec() 来加载另一个程序,我如何在父进程和子进程之间共享内存?

可以使用mmap吗?

现在父级和子级可以使用 mmap 正确共享内存,但在 exec 完成后

c linux fork exec mmap
2个回答
6
投票

如果孩子 已运行 exec() 来加载另一个程序?

通过

mmap()
创建的内存映射、通过
shm_open()
获得的 POSIX 共享内存段以及通过
shmat()
获得的 System V 共享内存段都不会在 exec 中保留。 这涵盖了我所知道的 Linux 提供的所有形式的共享内存。

因此,如果您希望子进程在

exec()
之后与父进程共享内存,那么子进程必须在 exec() 之后(重新)连接到适当的共享内存。 显然,这意味着无论由
exec()
启动的程序都必须编写来执行此操作。 (特别注意,成功后,exec 系列函数不会返回。)

可以使用mmap吗?

仅当孩子在
exec()

之后重新映射记忆时。


到目前为止,父级和子级可以使用 mmap 正确共享内存,但不能 执行完成后

这是设计使然。

更新

上面的原始答案是一个近似值。 内存映射和共享内存段附件确实不会在

exec()

中保留。 此外,通过

shm_open()
获得的 POSIX 共享内存段作为文件呈现给程序,默认设置了
FD_CLOEXEC
标志,因此在执行
exec()
时会自动关闭。
但是,

如果关闭了

exec()
    标志(通过
  • FD_CLOEXEC

    ),则

    POSIX 共享内存可以跨 
    fcntl()
    继承。 在这种情况下,仍然存在如何通知子文件描述符编号的问题,但有许多替代方案可用:命令行参数、环境变量、标准流上的 I/O、外部文件......它们的共同点是它们需要执行程序的积极参与,包括执行其自己的共享内存映射。
    
    

  • sysV 共享内存段的标识符(通过
  • shmget()

    获得)是全局的。 如果一个进程将其传递给另一个进程,那么第二个进程可以附加该段 (

    shmat()
    ),而无需执行自己的
    shmget
    
    

  • 因此,原始答案说子进程必须(重新)连接到共享内存,但基本细节实际上是子进程必须重新
映射

共享内存。 尽管如此,对于执行程序来说,简单地从头打开共享内存对象通常比通过这些方式之一获取它更方便。 您可以使用

shm_open

3
投票

int memFd = shm_open("example_memory", O_CREAT | O_RDWR, S_IRWXU); if (memFd == -1) { perror("Can't open file"); return 1; } int res = ftruncate(memFd, /*size of the memory block you want*/); if (res == -1) { perror("Can't truncate file"); return res; } void *buffer = mmap(NULL, /*size of the memory block you want*/, PROT_READ | PROT_WRITE, MAP_SHARED, memFd, 0); if (buffer == NULL) { perror("Can't mmap"); return -1; }


在另一个文件中:

int memFd = shm_open("example_memory", O_RDONLY, 0);
if (memFd == -1)
{
    perror("Can't open file");
    return 1;
}

void *buffer = mmap(NULL, /*size of the memory block you want*/, PROT_READ, MAP_SHARED, memFd, 0);
if (buffer == NULL)
{
    perror("Can't mmap");
    return -1;
}

在这些代码段之后,您可以使用

buffer
来访问共享内存。 (注意:它不需要是
void*

,您可以将其设置为指向您打算存储在共享内存中的任何内容的指针)

    

© www.soinside.com 2019 - 2024. All rights reserved.