在父子之间发送信息 – 为什么没有死锁?

鉴于此代码:

#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! 

我正在试着去理解pipe道,而有些事情我不清楚:

  1. 如果儿子在那一行发送他的消息, write(fd[1], string, (strlen(string)+1)); 之后我们有了printf来validation这个消息是否发送了,为什么我父亲从儿子那里收到消息之后 ,我得到了validation(例如: Verification : Message was sent successfully by the SON! 是不是应该首先从儿子证实 ,只有string?

  2. 如果父亲试图从pipe子上读书,而儿子想写信给pipe子,这里的某个地方隐藏着(我认为)僵局,不是吗? 为什么我没有陷入僵局?

谢谢

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

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

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

2)如果子进程没有写入任何东西到管道,那么是父母将阻塞(它不会像这样死锁)。

你的第一个问题:

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

答:如果有多个进程在运行,那么这些进程的指令的执行顺序是不确定的。 这取决于调度程序在哪个进程被调度的时候。 所以从程序的输出中,我们可以看到指令执行顺序如下:

CHILD-PROCESS: write(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 ?

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

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

当孩子写入管道时,内核将父母更改为运行状态。 看来,调度程序切换父母运行,之前子打印文本(可能在孩子从write呼叫返回之前)。

所以行

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

在行之前执行:

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

你可以通过使用strace -f命令来验证。

  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是否会先发生。 这取决于内核调度,不应该依赖。 但是如果管道处于Bock模式, C1和F1都是相关的。 相关= 两者都必须发生,否则会有死锁 。 以下情况会导致死锁。

  1. 孩子没有执行C1,而是做其他的事情,比如等待输入等等,不会返回,那么父母将在F1中被锁定。
  2. 父母不执行F1,而是做一些其他的事情,如等待输入等,不返回,那么孩子将在C1中死锁。

如果任何一个孩子/父母都离开了,那么你就会得到一个坏的管子/管子。