3

鉴于此代码:

#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验证消息已发送,为什么我在父亲收到儿子的消息Verification : Message was sent successfully by the SON! 得到验证(例如) ?不是应该先是儿子的验证,然后才是字符串吗?

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

谢谢

4

5 回答 5

3

你的第一个问题:

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

答:当您有多个进程在运行时,这些进程的指令执行顺序是不确定的。这取决于调度程序何时调度哪个进程。所以从你程序的输出中,我们可以知道指令执行顺序如下:

CHILD-PROCESS: 写(fd[1],字符串,(strlen(字符串)+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 ?

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

于 2012-07-16T12:22:48.810 回答
2

Because of I/O buffering, there is no guarantee that the output will be displayed in the order it was printed.

于 2012-07-16T11:51:15.390 回答
2

1)来自子进程的消息稍后出现的原因是因为写入管道可能会阻塞,直到缓冲区中有足够的空间(从这里开始):

如果一个进程试图写入一个完整的管道(见下文),那么 write(2) 会阻塞,直到从管道中读取足够的数据以允许写入完成。

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

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

于 2012-07-16T11:46:27.110 回答
1

When the child writes to the pipe, kernel changes the parent to running state. Seems that scheduler switch the parent to running, before the child prints the text (probably before child returns from write call).

So the line

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

is executed before line:

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

You can verify this by using strace -f command.

于 2012-07-16T11:53:23.413 回答
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 和 F1都是相关的。Related=两者都必须发生,否则会出现死锁。以下情况会导致死锁。

  1. 子进程不执行 C1,但执行其他操作,例如等待输入等并且不返回,则父进程将死锁在 F1 中。
  2. 父级不执行 F1,但执行其他操作(例如等待输入等)且不返回,则子级将死锁在 C1 中。

如果任何一个孩子/父母退出,那么我认为你会得到一个破管/信号管。

于 2012-07-16T12:13:30.330 回答