程序在调用fork()时陷入死锁

时间:2012-07-28 17:39:17

标签: c operating-system fork pipe shared-memory

我已经实现了一个基于共享内存的管道,我遇到了问题 尝试使用fork程序调用{​​{1}}。

以下主要内容:

main

正在使用共享内存库实现的匿名管道

当我按# include "my_shm_piper.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/shm.h> #include <semaphore.h> #include <sys/mman.h> int main() { int spd[2], pid, rb; char buff[4096]; fork(); // that fork is okay , but if we put it after initPipe() , there's a deadlock initPipe(); if (my_pipe(spd) < 0) { perror("my_pipe"); exit(1); } if (fork()) { rb = my_read(spd[0], buff, sizeof(buff)); if (rb > 0) write(1, buff, rb); } else { my_write(spd[1], "hello world!\n", sizeof("hello world!\n")); } my_close(spd[0]); my_close(spd[1]); removePipe(); return 0; } 命令1st时,如上所述,我的程序按预期工作,所有fork() - s都会显示。

但是当我在hello-world之后放置fork时,会出现死锁,程序会挂起:

initPipe()

我认为int main() { int spd[2], pid, rb; char buff[4096]; initPipe(); fork(); // now the fork() is after the initialization ,and we have a deadlock if (my_pipe(spd) < 0) { perror("my_pipe"); exit(1); } // from here the same as above } 的初始化阶段只发生一次,而不是 两次,如第一次fork()

我认为写作/阅读阶段出现了问题,但我似乎无法做到 找到确切的来源。

我很感谢你对此事的帮助

谢谢

修改

H.文件中的结构:

main()

这是initPipe:

struct PipeShm
{
    int init;
    int flag;
    sem_t *mutex;
    char * ptr1;
    char * ptr2;
    int status1;
    int status2;
    int semaphoreFlag;
};

这是my_pipe():

int initPipe()
{
    if (!myPipe.init)
    {
        myPipe.mutex = mmap (NULL, sizeof *myPipe.mutex, PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS, -1, 0);
        if (!sem_init (myPipe.mutex, 1, 1))
        {
            myPipe.init = TRUE;
        }
        else
            perror ("initPipe");
    }
    return 1;   // always successful
}

这是阅读:

int my_pipe(int spd[2])
{
    spd[0] = shmget(2009, SHMSIZE, 0);      // for reading
    spd[1] = shmget(2009, SHMSIZE, 0666 | IPC_CREAT);  // for writing

     if (spd[0] == -1 || spd[1] == -1)
     {
             perror("shmget");
             exit(EXIT_FAILURE);
             return -1;
     }

     return 1;

}

这是写作:

ssize_t my_read(int spd, void *buf, size_t count)
{

    char array[4096];
    memset (array, '\0', 4096);
    ssize_t returnVal = 0;

    sem_wait (myPipe.mutex);

    int sval;
    sem_getvalue (myPipe.mutex, &sval);

    printf ("my_read - wait %d\n", sval);
    if (sem_wait (myPipe.mutex))
    perror ("sem_wait");

    printf ("my_read - proceed\n");

    if (myPipe.flag == FALSE)
    {
        myPipe.ptr1 = shmat (spd, NULL, 0); // attaching the segment
        if (myPipe.ptr1 == (void *) -1)
            error_out ("shmat");

        strncpy (array, myPipe.ptr1, count);
        array[count] = '\0';

        returnVal = strlen (array);
        buf = (void *) array;

        printf ("Output:%s", array);

    }

    else if (myPipe.flag == TRUE)
    {
        const size_t region_size = sysconf (_SC_PAGE_SIZE);
        myPipe.ptr1 = mmap (0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, spd, 0);
        if (myPipe.ptr1 == (void *) -1)
            error_out ("mmap");

        strncpy (array, myPipe.ptr1, count);
        array[count] = '\0';

        returnVal = strlen (array);
        buf = (void *) array;

        printf ("Output:%s", array);

    }

    return returnVal;

}

过程就像那样 - 在第二个主要部分(这是控制台上的输出):

ssize_t my_write(int spd, const void *buf, size_t count)
{

       ssize_t returnVal = 0;
       sleep(1); // debug to ensure that read goes first for testing.
        if (myPipe.flag == FALSE)
        {
            myPipe.ptr2 = shmat (spd, NULL, 0); // attaching the segment
            if (myPipe.ptr2 == (void *) -1)
                error_out ("shmat");

            char *d = (char *) buf;

            returnVal = snprintf (myPipe.ptr2, count, "%s", d);
        }
        else
        {
            const size_t region_size = sysconf (_SC_PAGE_SIZE);

            // Map the region into memory.
            myPipe.ptr2 = mmap (0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, spd, 0);
            if (myPipe.ptr2 == MAP_FAILED)
                error_out ("mmap");
            char *d = (char *) buf;

            returnVal = snprintf (myPipe.ptr2, count, "%s", d);
        }

        sem_post (myPipe.mutex);
        return returnVal;

}

在第一个主要内容中,控制台中的输出是:

my_read - wait 0
my_read - proceed
Output:hello world!
// here it just gets stuck

2 个答案:

答案 0 :(得分:2)

阿。棘手的,但我很无聊,想出来。

基本上,你的等待和帖子不平衡。如果你看看你的read()函数,你会做两次等待:

sem_wait (myPipe.mutex);
// some more code
if (sem_wait (myPipe.mutex))
  perror ("sem_wait");

但是你的写功能只发一个帖子。

但是为什么如果fork发生在initPipe()之前呢?因为您正在将信号量初始化为1:

if (!sem_init (myPipe.mutex, 1, 1))

由于您在init之前进行了分叉,因此您有两个不同的信号量,其值为1;每个人都会收到一个帖子和两个等待,所以你很好。

在另一种情况下,您有一个值为1的信号量,它将收到两个帖子和四个等待。 1 + 2 < 4,因此您的一位读者会挂在sem_wait上。

BTW,这是一种非常复杂的写作方式pipe(2)

答案 1 :(得分:0)

鉴于“工作”代码,您有两个管道,每个管道有一个读取器和一个写入 鉴于'notworking'代码,你有一个管道有2个读者和2个编写器,并尝试两次创建相同的未命名管道。

当2位读者和2位作家时, 第二次创建相同的管道将返回-1并将errno设置为EEXISTS。