当我这样做:
myProgram.h
myProgram.c
struct PipeShm
{
// all my fields
// more
// ...
};
struct PipeShm myPipe = { /* initialization for all fields */ };
struct PipeShm * sharedPipe = &myPipe;
void func()
{
sharedPipe = mmap (NULL, sizeof * sharedPipe, PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS, -1, 0);
}
当我对指针sharedPipe进行mmap时,如果我从main()调用myProgram代码中的任何方法,那么所有进程是否会共享我与myPipe结构共享的确切共享内存?
或者每个新创建的孩子都会拥有自己的新myPipe吗?
问候
编辑:
这是在我阅读了评论&回答:现在进行了更改,我只在分配后才初始化段的值:
#include "my_pipe.h"
struct PipeShm * sharedPipe = NULL;
int shm_pipe_init()
{
if (!sharedPipe)
{
int myFd = shm_open ("/myregion", O_CREAT | O_TRUNC | O_RDWR, 0600);
if (myFd == -1)
error_out ("shm_open");
// Allocate some memory in the region - We use ftruncate, write(2) would work just as well
int retAlloc = ftruncate (myFd, sizeof * sharedPipe);
if (retAlloc < 0)
error_out("ftruncate");
sharedPipe = mmap (NULL, sizeof * sharedPipe,
PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS, myFd, 0);
if (!sem_init (&sharedPipe->semaphore, 1, 0))
{
sharedPipe->init = TRUE;
sharedPipe->flag = FALSE;
sharedPipe->ptr1 = NULL;
sharedPipe->ptr2 = NULL;
sharedPipe->status1 = -10;
sharedPipe->status2 = -10;
sharedPipe->semaphoreFlag = FALSE;
sharedPipe->currentPipeIndex = 0;
}
else
perror ("shm_pipe_init");
}
return 1; // always successful
}
然而问题仍然存在,共享内存似乎不是在进程之间共享,因为在运行和分叉主要时:
int main()
{
int spd, pid, rb;
char buff[4096];
fork();
shm_pipe_init();
// more
return 0;
}
我仍然得到输出,模拟只有一个进程正在运行的行为(而不是多个输出,我只得到一个或一对,取决于进程之间的竞争条件).
解决方法:
如果您打算多次调用此程序,答案是“否”.如果您打算在创建映射后进行分叉,则答案为“是”.
匿名映射没有底层文件.因此,创建匿名映射的进程无法指定特别需要哪个已存在的映射(这也不是预期的用法,您应该获得一个新的独立映射).因此对第一种情况“不”.
共享映射允许拥有相同映射的所有进程访问相同的phsyical内存.这意味着,如果在创建映射后进行fork,那么fork将主要以通常的方式工作,将进程拥有的所有页面标记为copy-on-write,但映射中的页面除外.父节点和子节点都将保留映射页面,并且能够通过指针访问相同的物理内存(这意味着页面甚至会有相同的虚拟地址 – 这通常不是你可以依赖的东西在映射文件时,但在这种情况下,操作系统别无选择,只能确保这种情况).
关于匿名和共享映射的组合或者究竟应该发生什么,联机帮助页仍然含糊不清,但TLPI第49.7章明确提到了MAP_SHARED | MAP_ANONYMOUS:
[…] followed by a call to fork(), then, because the child produced by fork() inherits the mapping, both processes share the memory region.
因此对于第二种情况是“是”.
Re:编辑过的帖子
顺序错误:
fork();
shm_pipe_init();
首先分叉然后初始化共享内存.这将分别创建一个共享(读取为可共享,可以在以后共享,如果进程再次分叉,但它不会神奇地与父级共享!)映射为每个进程.
然后,您有两个映射,每个进程一个映射,它们将由各自的子进程和孙进程共享(如果有的话),但这对于实现您想要的内容没有任何帮助.它们是“共享”的事实并不重要,它们是不同的映射,并且对于相应的其他过程是未知的.
首先创建映射,然后fork.这将创建一个共享映射,两个进程确实拥有/共享并可用于预期目的.
(此外,你对fork的使用并没有严格错误,但有点奇怪…你通常应该检查返回值,所以你知道哪一个是父,哪一个是孩子.而且它不像fork当然,如果这根本无关紧要,因为父母和孩子总是100%完全相同而且你不关心失败,那就没问题.通常情况下,人们通常想知道.)