2012-07-16 100 views
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. 如果父親試圖從管道讀取,並且兒子想寫入管道,在這裏的某個地方隱藏(我認爲)是死鎖,不是嗎?爲什麼我沒有陷入僵局?

由於

回答

2

1)從子過程中的消息出現之後是因爲寫入到一個管道可以被阻塞,直到有在緩衝足夠的空間(從here)其原因是:

如果進程嘗試寫入完整管道(請參閱下面的 ),然後寫入(2)塊,直到從管道 中讀取足夠的數據以允許寫入完成。

換句話說,子進程等待父進程在write()調用中讀取消息。 2)如果子進程沒有向管道寫任何東西,那麼是的,父進程將被阻塞(它不會像這樣死鎖)。

+0

儘管Linux下的管道緩衝區是16kB,這對於保存一個48字節的消息應該足夠了(所以在這個例子中應該確實是_never_block)。我認爲這實際上只是一個調度/併發artefact。 – Damon 2012-07-16 12:14:39

+0

@達蒙是的,這似乎很可能。 – trojanfoe 2012-07-16 12:15:34

2

由於I/O緩衝,不能保證輸出將按打印順序顯示。

+0

+1我只是想說在這種情況下這是不正確的,但是在再次閱讀之後......也許如果你對它進行了輕微的改寫,它就是_quite_正確的。管道上的「寫入」過程中沒有緩衝。但是,像所有C標準lib I/O一樣,'printf'肯定是緩衝區。由於'printf'已經在'write'之後執行,但是緩衝所增加的不確定性並不影響它們的順序。儘管如此,另一個線程也使用'printf',所以人們可以說,你是對的(或者至少沒有錯)。但是它可能同樣(或更多)可能只是一種調度製品而已。 – Damon 2012-07-19 09:42:03

1

當孩子寫入管道時,內核會將父級更改爲運行狀態。 似乎在孩子打印文本之前(可能在孩子從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命令進行驗證。

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是相關的,如果管道處於bock模式。相關= 都必須發生,否則會出現死鎖。以下情況會導致死鎖。

  1. 孩子沒有執行C1,但做了其他的事情,如等待輸入等&不返回,那麼父母將在F1中死鎖。
  2. 父母不執行F1,而是做其他事情如等待輸入等&不返回,則子將在C1中死鎖。

如果孩子/父母退出,那麼你會得到一個破管/ sig-pipe我認爲。

3

你的第一個問題:

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)); (「我是父親,我收到了字符串:%s」,readbuffer);

CHILD-PROCESS: printf(「驗證:消息由SON成功發送!\ n」);

這個序列可能與其他時間不同。

你secod問題:

2. Why am I not getting a deadlock ?

答:在這種情況下,父進程只有幾個街區等在管道上一些輸入。但孩子可以寫,不必等待。所以沒有死鎖的機會。

+0

謝謝,當存在死鎖時,你能舉個例子嗎? – ron 2012-07-16 12:27:13

相關問題