【问题标题】:Program goes into a deadlock when invoking fork()调用 fork() 时程序陷入死锁
【发布时间】:2012-07-27 01:04:35
【问题描述】:

我已经实现了一个基于共享内存的管道,但当我遇到问题时 尝试使用main 程序调用fork

以下主要内容:

# 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;
}

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

当我像上面那样输入fork()1st 命令时,那么我的程序按预期工作,所有hello-world-s 都会出现。

但是当我把 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() 的初始化阶段只发生一次,而不是 两次,如第一次 main()

我猜写作/阅读阶段有问题,但我看不到 找到确切的来源。

感谢您对此事的帮助

谢谢

编辑:

H.文件中的结构:

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

这是 initPipe:

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
}

这是 my_pipe():

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

在第一个 main 中,控制台的输出是:

my_read  - wait 0
my_read  - wait 0
my_read - proceed
my_read - proceed
Output:hello world!
Output:hello world!
// here the program is done , the end 

【问题讨论】:

  • 您是在对fork() 的实际调用中陷入僵局,还是说您只是在之后不通过管道打印您的行?您是否尝试过在fork 调用之后立即向stderr 输出语句来检查对fork 的调用是否连续进行?
  • @Jason:我是说在2nd main 中,只有hello-world 出现一次,程序继续,但什么也没发生。我认为读/写只是挂在那里等待永远不会发生的事情。
  • 如果不看 initPipes() 的作用,就很难猜出发生了什么;我假设这两个叉子是你真正想要的。您是否尝试过使用调试器查看进程挂起的位置?
  • 剩下的代码在哪里?答案怎么会引用不存在的代码?例如,第一个答案引用了一行:sem_wait
  • @hebbo 问题已编辑;你可以通过查看历史来查看原始代码。

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


【解决方案1】:

给定“工作”代码,您有两个管道,每个管道都有一个读取器和一个写入器 给定“不工作”的代码,您有一个具有 2 个读取器和 2 个写入器的管道,并尝试创建相同的未命名管道两次。

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

【讨论】:

  • 剩下的代码在哪里?答案怎么会引用不存在的代码?例如,第一个答案引用了一行:sem_wait
【解决方案2】:

啊。棘手的一个,但我很无聊,想弄清楚。

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

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

但是你的 write 函数只发一篇文章。

但是,如果分叉发生在initPipe() 之前,为什么它会起作用?因为您将信号量初始化为 1:

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

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

在另一种情况下,您有一个值为 1 的信号量,它将接收两个帖子和四个等待。 1 + 2 &lt; 4,所以你的一位读者会继续关注sem_wait

顺便说一句,pipe(2) 的写法相当复杂。

【讨论】:

  • 知道了,然后删除if (sem_wait (myPipe.mutex)) perror ("sem_wait"); 就足够了,我猜...? 10x
  • 那个,你不应该将你的信号量初始化为 1。
  • 坦率地说,发生了一些奇怪的事情:一次我得到 1 hello-world 而在另一次运行中我得到 2 hello-world-s,交替进行。
  • 剩下的代码在哪里?答案怎么会引用不存在的代码?例如,第一个答案引用了一行:sem_wait
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多