所以我有一個程序創建一個子進程並執行一個命令(例如ls)。父母然後將使用管道發送和從孩子獲得。當我從命令行自己輸入命令時,這工作正常。C IPC等待孩子
但是,當輸入來自文件時,看起來孩子沒有足夠的時間運行,並且從管道讀取時我得到NULL - 即使會有信息來自它。
使用睡眠()的缺點,有沒有更好的方法來確保孩子在嘗試讀取它之前已經運行?
非常感謝!
所以我有一個程序創建一個子進程並執行一個命令(例如ls)。父母然後將使用管道發送和從孩子獲得。當我從命令行自己輸入命令時,這工作正常。C IPC等待孩子
但是,當輸入來自文件時,看起來孩子沒有足夠的時間運行,並且從管道讀取時我得到NULL - 即使會有信息來自它。
使用睡眠()的缺點,有沒有更好的方法來確保孩子在嘗試讀取它之前已經運行?
非常感謝!
如果沒有設置你管文件描述符非阻塞的,那麼就應該沒有問題。任何對管道的讀取都會阻塞,直到孩子產生輸出;如果需要響應多個文件描述符(例如,來自用戶的標準輸入和來自子進程的管道),請使用select()
或poll()
。
我認爲它是fgets()
返回NULL。這表示文件結束(意味着孩子已經關閉了管道的末端),或者是錯誤。您可以使用feof()
或ferror()
來檢查其中哪些爲真。在錯誤情況下使用perror()
來查看錯誤實際是什麼。
問題是你對孩子有多少控制?如果你自己寫孩子,那麼你可以讓孩子在共享內存中設置一個標誌,它已經開始(或觸摸一個文件或任何你喜歡的癢癢),然後只有當你知道孩子在線運行它。
如果您對孩子沒有控制權,仍然可以通過用自己的腳本包裝孩子來實現上述解決方案,該腳本首先啓動孩子,然後設置共享內存,這可以採用一個shell腳本如下
#!/bin/sh
$CHILD
my_app_that_set_the_flag
最後另一種選擇是繼續等待aslong當你從管空,顯然這會導致一個無限循環,但如果你不能garuntee,你總是會得到的東西管道
您的父線程需要等到孩子準備好再嘗試重新廣告來自管道。有幾種方法可以做到這一點。
首先,您可以使用條件變量。聲明兩個線程都可以訪問的變量並將其設置爲0
。準備父母閱讀時,您的子線程會將其設置爲1
。父母將等待,直到變量變爲1
(使用諸如while(!condvar) sleep(1);
之類的東西),然後它將從管道讀取並將變量重置爲0
,以便孩子知道父母完成。
另一種選擇是使用進程間通信的一種形式,如signals。與條件變量方法類似,子線程將執行其工作,然後在完成時向父線程發送信號。父線程將等待,直到它從管道讀取信號之前接收到信號,然後它可以發回一個信號給孩子,表明它已完成。
編輯:既然你產卵子進程與fork
,而不是與線程,您不能使用條件變量在這裏(父母和孩子都會有它獨立的副本)。
相反,您可以使用signal()
和kill()
函數在進程之間發送信號。在分叉之前,使用getpid
來存儲父級PID的副本(用於子進程)。同時存儲返回值fork
,因爲它將包含孩子的pid。
發送信號到其它進程,使用類似:
kill(parent_pid, SIGUSR1);
接收過程需要建立一個信號處理程序。例如:
int signal_received = 0;
void signal_handler(int signal_num) {
if (signal_num == SIGUSR1)
signal_received = 1;
}
signal(SIGUSR1, signal_handler);
功能signal_handler
現在將被自動調用每當過程接收信號編號SIGUSR1
。你的線程會等待在一個循環中,看着這個變量使用類似的改變:
while (1) { // Signal processing loop
// Wait here for a signal to come in
while (!signal_received) { sleep(1); }
// Wake up and do something
read_from_pipe();
...
signal_received = 0;
}
您可以簡單地使用'select()'等待管道可讀。 – caf 2010-04-29 23:53:06
@caf:是的,但只是告訴你有什麼需要閱讀的東西。 select()'告訴你,你可以並不意味着你所有的數據都在那裏。許多時候,等待所有內容都準備好被讀取比讀取內容時更容易,然後嘗試將它重新組合在一起(特別是如果數據本身不能告訴你在哪裏結束是)。 – bta 2010-04-29 23:59:30
這似乎是最簡單的解決方案,所以我嘗試了它 - 但無法讓它工作。這個變量是在我做了fork之後被聲明的,並且在孩子中發生了變化,但是父母似乎根本沒有看到變化。這可能與我在兒童中使用exec有關嗎? – Gary 2010-04-30 01:51:51
應該提到文件描述符是非阻塞的。我這樣做是因爲當沒有新數據時,從fgets()中讀取數據被阻塞,導致程序永遠等待。 – Gary 2010-04-30 00:15:26
@Gary:在這種情況下,使用'select()'將文件描述符添加到您正在監視的文件描述符集中 - 例如,如果您想等待來自用戶或來自管道的輸入,請使用'select )'來監視stdin和管道。 – caf 2010-04-30 00:20:39
在這種情況下,我只想從一個文件描述符輸入而不是標準輸入,所以我不認爲我需要選擇?基本上我只是想給孩子足夠的時間來運行它的命令,如果它仍然是NULL,就把它當作錯誤來處理。 – Gary 2010-04-30 01:47:56