在父亲和父亲之间发送消息儿子 - 为什么没有死锁?

时间:2012-07-16 11:41:43

标签: c linux pipe

鉴于此代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(void)
{
        int     fd[2], nbytes;
        pid_t   childpid;
        char    string[] = "Hello, world! I'm the son and this my message!\n";
        char    readbuffer[80];

        pipe(fd);   // piping fd[0] & fd[1]

        if((childpid = fork()) == -1)   // here we create a SON process
        {
                perror("fork");
                exit(1);
        }

        if(childpid == 0)    // child process
        {
                /* Child process closes up input side of pipe */
                close(fd[0]);       // closing the READ end from reading , after that the SON would write into fd[1]

                /* Send "string" through the output side of pipe */
                write(fd[1], string, (strlen(string)+1));
                printf("Verification : Message was sent successfully by the SON!\n");
                exit(0);
        }
        else    // father process
        {
                /* Parent process closes up output side of pipe */
                close(fd[1]);

                /* Read in a string from the pipe */
                nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
                printf("I'm the father and I received that string: %s", readbuffer);
        }

        return(0);
}

输出结果为:

I'm the father and I received that string: Hello, world! I'm the son and this my message!
Verification : Message was sent successfully by the SON!

我正在试图理解管道,我很少有事情不清楚:

  1. 如果儿子在该行write(fd[1], string, (strlen(string)+1));发送了他的消息,之后我们有printf验证消息是否已发送,为什么我会得到验证(例如{{1}父亲收到儿子的消息之后 是不是假设首先来自儿子的验证,然后才是字符串?

  2. 如果父亲试图从管道中读取并且儿子想要写入管道,那么这里的某处隐藏(我认为)死锁,不是吗?为什么我没有陷入僵局?

  3. 谢谢

5 个答案:

答案 0 :(得分:3)

你的第一个问题:

1. wasn't it suppose to be first the verification from the son and only then the string ?

答案:当您运行多个进程时,这些进程的指令执行顺序不确定。这取决于调度程序何时进行调度。因此,从程序的输出中,我们可以按如下方式告诉指令执行顺序:

CHILD-PROCESS:写(fd [1],string,(strlen(string)+1));在此指令之后,此过程暂停

PARENT-PROCESS: nbytes = read(fd [0],readbuffer,sizeof(readbuffer));

PARENT-PROCESS: printf(“我是父亲,我收到了那个字符串:%s”,readbuffer);

CHILD-PROCESS: printf(“验证:消息由SON成功发送!\ n”);

这个序列也可能不同以及其他时间。

你的问题:

2. Why am I not getting a deadlock ?

答案:在这种情况下,父进程只是阻塞等待管道上的某些输入。但孩子可以写,它不必等待。所以没有死锁的可能。

答案 1 :(得分:2)

1)来自子进程的消息之后的原因是因为写入管道可能会阻塞,直到缓冲区中有足够的空间(来自here):

  

如果进程尝试写入完整管道(请参阅          在下面),然后写入(2)块,直到从管道读取了足够的数据          允许写完成。

换句话说,子进程等待父进程在write()的调用中读取消息。

2)如果子进程无法向管道写入任何内容,那么父进程将阻塞(它不会死锁)。

答案 2 :(得分:2)

由于I / O缓冲,无法保证输出将按照打印顺序显示。

答案 3 :(得分:1)

当孩子写入管道时,内核会将父级更改为运行状态。 似乎调度程序在父项打印文本之前将父项切换为运行(可能在子项从write调用返回之前)。

所以行

printf("I'm the father and I received that string: %s", readbuffer);

在line:

之前执行
printf("Verification : Message was sent successfully by the SON!\n");

您可以使用strace -f命令验证这一点。

答案 4 :(得分:1)

    if(childpid == 0)    // child process
    {
            write(fd[1], string, (strlen(string)+1)); #C1
            printf("Verification : Message was sent successfully by the SON!\n"); #C2
            exit(0);
    }
    else    // father process
    {
            /* Read in a string from the pipe */
            nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); #F1
            printf("I'm the father and I received that string: %s", readbuffer); F2
    }

在上述情况下,我们无法确定是先发生 C1还是F1 。它取决于内核调度,不应该依赖。但是 C1&amp;如果管道处于bock模式,F1 是相关的。相关= 两者都必须发生,否则会出现死锁。以下情况会导致死锁。

  1. 孩子没有执行C1,而是做其他事情,比如等待输入等等。没有回来,那么父母将被锁定在F1中。
  2. 父母没有执行F1,而是做其他事情,比如等待输入等&amp;没有回来,那么孩子就会死在C1中。
  3. 如果孩子/父母退出,那么你会得到一个破管/ sig-pipe。