2011-07-08 51 views
3

所以我試圖在fork()之後的子進程上運行一個系統命令(或者exec,或者其他),然後向它推入一些輸入,然後得到它的輸出。它在fork()後面看起來像這樣,pc和cp是父子和父子管道。現在pipe,fork和non-blocking IPC

case 0: 
     /* Child. */ 
     close(STDOUT_FILENO); /* Close current stdout. */ 
     dup2(cp[1], STDOUT_FILENO); 

     close(STDIN_FILENO); 
     dup2(pc[0], STDIN_FILENO); 

     close(pc[1]); 
     close(cp[0]); 
     execlp("cat", "cat", NULL); 
     exit(1); 
    default: 
     /* Parent. */ 
     /* Close what we don't need. */ 
     printf("Input to child:\n"); 

     string theinput("Hey there baby"); 
     write(pc[1], theinput.c_str(), theinput.size()); 
     close(pc[1]); 

     cout << "The input : " << theinput << endl; 


     printf("\nOutput from child:\n"); 
     close(cp[1]); 
     while(read(cp[0], &ch, 1) == 1) 
     { 
      write(1, &ch, 1); 
      outcount++; 
     } 

     exit(0); 

,似乎很好地工作(如果你想要的代碼:http://pastebin.com/Fh7GrxYm),但是當我在#posix在IRC聊天,他們會瘋了,怎麼這會潛在地阻止了,怎麼了「取決於內核如何感覺」。

有同樣的事情的MSDN博客文章:http://blogs.msdn.com/b/oldnewthing/archive/2011/07/07/10183884.aspx

一個如何防止堵塞,如果有的話,等?

回答

1

在你的情況下,當父進程到達這條線可能會出現僵局:

​​

如果「theinput的」是一個很大的數據,那麼父進程可能會填滿pc管。子進程(這裏的cat)可能會讀取其中的一部分,但不是全部。 cat他們會回聲給你。但是,如果數據量很大,它可能會填滿管道並阻塞,直到有人從管道中讀取數據。這將永遠不會發生,因爲父進程被阻塞,等待pc管道耗盡,並且永遠不會到達消耗cp管道內容的代碼。僵局。

就像你的IRC好友說的那樣,這是否發生取決於很多事情,例如涉及的數據量,管道在阻塞之前可以容納的數據量(依賴於內核的參數),數量標準輸入輸出或者由父母或子女的過程等進行其他的緩衝...的

的選項有:

  1. 使用兩種方法來控制外部命令:一個餵它數據,一個讀取結果回來了。你必須爲此fork()兩次。這看起來很像一個shell管道。通常,最終的數據源是孫子過程,過濾器是中間父輩,並且是授予過程的最終數據匯。

  2. 使用兩個線程來控制外部命令。與之前的選項類似。

  3. 使用非阻塞I/O來控制外部命令。使用fcntl()將兩個文件描述符設置爲非阻塞模式,並使用poll()select()設置事件循環等待任一文件描述符準備就緒。當任一文件描述符準備好時,準備好write()以完成部分操作,並且read()不能一次讀取所有內容。

  4. 使用現有的事件循環像glib's,建立你的水管爲IO Channels,並且watch them知道什麼時候它的時間來讀取或寫入數據。與之前的選項類似,但使用現有的框架,因此您可以與現有的應用程序事件循環集成。

BTW:你exit(1)_exit(1)防止C庫在短暫的子進程調用不恰當的退出時間掛鉤。