[英]Why to use non-blocking waitpid instead of blocking wait?
我正在閱讀https://www.amazon.com/Unix-Network-Programming-Sockets-Networking/dp/0131411551 ,作者在那里處理調用waitpid
而不是wait
的處理程序中的sigchld
。
在圖 5.7 中,我們不能在循環中調用 wait,因為如果有運行的子進程尚未終止,則無法阻止 wait 阻塞。
處理程序如下:
void sig_chld(int signo)
{
pid_t pid;
int stat;
// while ((pid = wait(&stat)) > 0)
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
{
printf("child %d terminated\n", pid);
}
}
問題是,即使我使用wait
的阻塞版本(如注釋掉的那樣),孩子無論如何都會被終止(這是我想要的,以便沒有僵屍),那么為什么還要打擾它是否處於阻塞方式還是非阻塞?
我假設當它是非阻塞方式時(即使用waitpid
),那么我可以多次調用處理程序? (當一些孩子被終止,而其他孩子仍在運行時)。 但是我仍然可以阻止並在該處理程序中等待所有孩子終止。 因此,多次或僅調用一次處理程序沒有區別。 還是有任何其他非阻塞和多次調用處理程序的原因?
while 循環條件將比需要等待的僵屍子進程多運行一次。 因此,如果您使用帶有WNOHANG
標志的wait()
而不是waitpid()
,如果您有另一個仍在運行的子進程,它可能會永遠阻塞 - 因為如果根本沒有子進程, wait()
只會提前返回ECHLD
錯誤. 一個健壯的通用處理程序將使用waitpid()
來避免這種情況。
想象一個父進程啟動多個子進程做各種事情的情況,並定期向他們發送關於做什么的指令。 當第一個退出時,在SIGCHLD
處理程序的循環中使用wait()
將導致它永遠阻塞,而其他子進程正在等待更多他們永遠不會收到的指令。
或者,比如說,一個inetd
服務器,它監聽網絡連接並派生一個新進程來處理每個連接。 有些服務可以快速完成,有些可以運行數小時或數天。 如果它使用信號處理程序來捕獲退出的子進程,那么如果您在循環中使用wait()
一旦該處理程序被退出的短期服務進程觸發,它將無法執行任何其他操作,直到長期存在的子進程退出.
我花了一秒鍾才明白問題出在哪里,所以讓我把它拼出來。 正如其他人所指出的, wait(2)
可能會阻塞。 如果指定了WNOHANG
選項, waitpid(2)
將不會阻塞。
您說對wait(2)
的第一次調用不應該阻塞是正確的,因為只有在子退出時才會調用信號處理程序。 但是,當調用信號處理程序時,可能有幾個孩子可能已經退出。 信號是異步傳遞的,並且可以合並。 因此,如果兩個子進程幾乎同時退出,操作系統可能只向父進程發送一個信號。 因此,必須使用循環來迭代地檢查是否有多個孩子退出。
現在我們已經確定循環對於檢查是否有多個子節點已經退出是必要的,很明顯我們不能使用wait(2)
,因為如果有一個子節點沒有退出,它將在第二次迭代中阻塞。
TL;DR 循環是必要的,因此使用waitpid(2)
是必要的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.