在尝试解决一些调试问题时,我在代码中添加了一些printf
- :
我使用了那段代码:
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
似乎共享内存不是那么共享的,为什么?
由于MAP_SHARED | MAP_ANONYMOUS
,所有流程之间共享细分受众群,因此为什么两个流程都具有相同的before
和after
值?
似乎每个进程都有自己的信号量,即使它们之间是共享的,所以出了什么问题?
谢谢
答案 0 :(得分:4)
由于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标志),但这不能移植到其他系统。
Per Karoly对另一个答案的评论,在公开电话中也有因O_TRUNC而出现竞争状况。如果第二个线程在第一个线程已经开始修改信号量后调用open
,则该TRUNC将破坏信号量状态。可能最好的解决方案是将代码创建,打开和mmaping共享内存移动到另一个名为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 :(得分:2)
一些想法......
我认为这是对POSIX信号量如何工作的一个有趣的误解。我没有看到sem_init
或sem_open
的来电。如果没有比你做得更明确,那么你不应该跨进程使用它们。
我对Linux上的mmap
的实现并不是那么新鲜,以及MAP_ANONYMOUS
可能会如何影响这一点,但一般来说,对映射区域的写入实际上并不是即时的。 manpage on linux.die says:
MAP_SHARED
分享这个映射。映射的更新对于映射此文件的其他进程是可见的,并且会传递到基础文件。在调用msync(2)或munmap()之前,实际上可能不会更新该文件。
原因是你的内存访问陷入了页面错误,此时内核将从文件描述符中填充内容,然后让你在RAM中写入,然后在稍后的某个时候内核将刷新回到文件描述符。