在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
    ,该段在所有进程之间共享,那么为什么两个进程在
    之前和之后都有相同的
    值呢

  • 似乎每个进程都有自己的信号量,即使它们之间共享了信号量,那么出了什么问题

  • 谢谢

    想一想

  • 我认为这是对POSIX信号量如何工作的根本误解。我没有看到调用
    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();