共享内存不与C中的进程共享

在尝试解决一些debugging问题时,我在代码中添加了一些printf -s:

我用这个代码:

 struct PipeShm { int init; sem_t sema; ... ... } struct PipeShm * sharedPipe = NULL; 

FUNC2:

 int func2() { if (!sharedPipe) { int myFd = shm_open ("/myregion", O_CREAT | O_TRUNC | O_RDWR, 0666); if (myFd == -1) error_out ("shm_open"); // allocate some memory in the region in the size of the struct int retAlloc = ftruncate (myFd, sizeof * sharedPipe); if (retAlloc < 0) // check if allocation failed error_out("ftruncate"); // map the region and shared in with all the processes sharedPipe = mmap (NULL, sizeof * sharedPipe,PROT_READ | PROT_WRITE,MAP_SHARED , myFd, 0); if (sharedPipe == MAP_FAILED) // check if the allocation failed error_out("mmap"); // put initial value int value = -10; // get the value of the semaphore sem_getvalue(&sharedPipe->semaphore, &value); if (sharedPipe->init != TRUE) // get in here only if init is NOT TRUE ! { if (!sem_init (&sharedPipe->semaphore, 1, 1)) // initialize the semaphore to 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; printf("\nI'm inside the critical section! my init is: %d\n" , sharedPipe->init); } else perror ("shm_pipe_init"); printf("\nI'm out the critical section! my init is: %d\n" , sharedPipe->init); } } return 1; // always successful } 

有了这个主要:

 int main() { int spd, pid, rb; char buff[4096]; fork(); func2(); return 0; } 

得到这个:

shm_pipe_mkfifo:文件存在

 I'm inside the critical section! my init is: 1 I'm out the critical section! my init is: 1 Output:hello world! I'm inside the critical section! my init is: 1 I'm out the critical section! my init is: 1 

似乎共享内存不那么共享,为什么?

  1. 该段由于MAP_SHARED | MAP_ANONYMOUS而在所有进程之间共享 MAP_SHARED | MAP_ANONYMOUS ,为什么两个进程after值和before都相同?

  2. 似乎每个进程都有自己的信号量,尽pipe它们之间是共享的,那么出了什么问题呢?

谢谢

由于您将MAP_ANONYMOUS标志用于mmap ,因此myFd参数将被忽略,并且会在每个进程中创建两个独立的共享内存块,这些块之间没有任何关系。

  MAP_ANONYMOUS The mapping is not backed by any file; its contents are initial‐ ized to zero. The fd and offset arguments are ignored; however, some implementations require fd to be -1 if MAP_ANONYMOUS (or MAP_ANON) is specified, and portable applications should ensure this. The use of MAP_ANONYMOUS in conjunction with MAP_SHARED is only supported on Linux since kernel 2.4. 

如果你摆脱了MAP_ANONYMOUS那么你将只有一个共享的内存块,但是你有没有调用sem_init的问题。 在使用NPTL的Linux上,它实际上可以工作,因为将sem_t清除为全0字节(这里的初始状态)等同于sem_init(&sema, anything, 0); (NPTL忽略pshared标志),但这不能移植到其他系统。

根据Karoly对另一个答案的评论,在公开电话会议上也有O_TRUNC的竞赛状况。 如果在第一个线程已经开始修改信号量之后第二个线程调用open ,那么TRUNC将会破坏信号量状态。 可能最好的解决方案是将创建,打开和压缩共享内存的代码移动到另一个名为BEFORE调用fork的函数中。

编辑

要修复O_TRUNC问题,不能有多个进程使用O_TRUNC调用shm_open。 但是,如果你只是摆脱了O_TRUNC,那么你有启动问题,如果共享内存对象已经存在(从以前的程序运行),它可能不会处于可预测的状态。 在可能性上是分裂开始的func2:

 main() { func1(); fork(); func2(); } func1() { int myFd = shm_open ("/myregion", O_CREAT | O_TRUNC | O_RDWR, 0666); if (myFd == -1) error_out ("shm_open"); // allocate some memory in the region in the size of the struct int retAlloc = ftruncate (myFd, sizeof *sharedPipe); if (retAlloc < 0) // check if allocation failed error_out("ftruncate"); // map the region and shared in with all the processes sharedPipe = mmap (NULL, sizeof *sharedPipe, PROT_READ|PROT_WRITE, MAP_SHARED, myFd, 0); if (sharedPipe == MAP_FAILED) // check if the allocation failed error_out("mmap"); } func2() { // put initial value int value = -10; // get the value of the semaphore sem_getvalue(&sharedPipe->semaphore, &value); : 

或者你可以保持相同的代码(只是摆脱O_TRUNC),并在fork之前添加一个清理:

 main() { shm_unlink("/myregion"); fork(); func2(); 

在所有情况下,如果您同时运行程序的多个副本,您仍然会遇到问题。

一些想法…

  1. 我认为这是POSIX信号量如何工作的一个有趣的误解。 我没有看到对sem_initsem_open的调用。 你不应该能够跨越流程使用它们,而不会比你做得更明确。

  2. 我在Linux上实现mmap并不是那么新鲜, MAP_ANONYMOUS可能会对此产生影响,但通常写入映射区域并不是真正的瞬间。 linux.die上的manpage说 :

MAP_SHARED
分享这个映射。 映射的更新对映射此文件的其他进程可见,并被传送到底层文件。 在调用msync(2)或munmap()之前,文件可能不会实际更新。

原因是你的内存访问被困在一个页面错误中,此时内核将填充文件描述符中的内容,然后让你在RAM中写入内容,然后在稍后的某个时刻内核会刷新到文件描述符。