在C中,共享内存与进程的共享程度不高
在尝试解决一些调试问题时,我在代码中添加了一些在C中,共享内存与进程的共享程度不高,c,linux,operating-system,fork,shared-memory,C,Linux,Operating System,Fork,Shared Memory,在尝试解决一些调试问题时,我在代码中添加了一些printf-s: 我使用了这个代码: struct PipeShm { int init; sem_t sema; ... ... } struct PipeShm * sharedPipe = NULL; 职能2: int func2() { if (!sharedPipe) { int myFd = shm_open ("/myregion", O_CREAT | O_TRUNC |
printf
-s:
我使用了这个代码:
struct PipeShm
{
int init;
sem_t sema;
...
...
}
struct PipeShm * sharedPipe = NULL;
职能2:
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
}
得到这个:
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
,该段在所有进程之间共享,那么为什么两个进程在之前和之后都有相同的值呢
sem\u init
或sem\u open
。如果不做比以前更明确的事情,就不能跨流程使用它们mmap
在Linux上的实现以及MAP\u ANONYMOUS
可能会对其产生的影响,我并不太了解,但一般来说,对映射区域的写入不可能是即时的。委员会:共享此映射。对映射的更新对映射此文件的其他进程可见,并且会一直执行到基础文件。在调用msync(2)或munmap()之前,可能不会实际更新该文件。
这是因为您的内存访问被困在一个页面错误中,此时内核将填充文件描述符中的内容,然后让您在RAM中进行写操作,然后在稍后的某个时候内核将刷新回文件描述符。因为您使用
MAP\u ANONYMOUS
标志来mmap
,myFd
参数将被忽略,您将创建两个独立的共享内存块,每个进程中一个,它们彼此没有关系
如果您去掉MAP\u ANONYMOUS
,那么您将只有一个共享内存块,但是您会遇到不调用sem\u init
的问题。在使用NPTL的Linux上,它实际上可以工作,因为将sem_t清除为所有0字节(此处的初始状态)相当于sem_init(&sema,anything,0)代码>(NPTL忽略pshared标志),但这不能移植到其他系统
根据Karoly对另一个答案的评论,公开赛上还有一个比赛条件。如果第二个线程在第一个线程已经开始修改信号量之后调用open
,则该TRUNC将关闭信号量状态。最好的解决方案可能是将创建、打开和管理共享内存的代码移动到调用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\u TRUNC
。刷新不是问题,他不从磁盘读取数据,它不是一个真正的文件;这是共享内存。在同一个RAM中,映射到两个不同的进程。你是正确的,这里的错误是:(a)没有用pshared=1调用sem_init,和(b)使用MAP_匿名,这在本例中是错误的;你为什么坚持不这么做?@KarolyHorvath:Updated,请看帖子的结尾。@ron,鉴于你从so上获得的帮助数量,在提交完成的项目时,你真的应该表明你是代码的合著者:)@hristoilev:保留所有权利给so…@hristoilev:BTW我的朋友,我从不要求任何人帮我解决硬件问题。我总是问一个问题,我在哪里展示了我的代码,到目前为止我做了什么,我如何避免这里的竞争条件?他们确实是racing@ron:将赛车代码(至少shm_open,可能还有ftruncate和mmap)移动到一个单独的函数中,该函数在fork之前只调用一次。感谢您的大力帮助,但有一点仍然不太清楚:如果我想用我的程序运行多个进程,让我们举一个基本的例子,在func2()?坦率地说,我仍然在尝试用你的好建议来改进我的代码,但是我仍然得到了一些比赛条件。。。
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.
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);
:
main() {
shm_unlink("/myregion");
fork();
func2();