首先,讓我們先來回顧一下有關程序等待的知識。
所謂程序等待,說的就是父程序等待子程序:
如圖,父程序呼叫wait和waitpid函式等待子程序,從而清理系統中的殭屍程序。在此過程中,父程序可以阻塞等待子程序結束,也可以非阻塞地查詢是否有子程序結束等待清理(也就是輪詢的方式)。
若採用阻塞等待方式,父程序就不能處理自己的工作了;採用非阻塞方式,父程序在處理自己工作的同時還要時不時地輪詢⼀下子程序狀態,程式實現複雜。
sigchld是linux系統訊號列表中定義的第17號訊號:
事實上,程序等待不只是上面描述的那樣,子程序在終止時會給父程序發sigchld訊號,因為⼦程序終止是乙個非同步事件,所以發生這種訊號也是核心向父程序發的非同步通知。而大多數父程序對該訊號的預設處理動作是忽略。
儘管如此,父程序還是可以自定義sigchld訊號的處理函式,這樣它只需專心處理自己的工作,而不必關⼼子程序了, 子程序終止時會通知父程序,父程序在訊號處理函式中呼叫wait清理子程序即可。
有了程序等待和sigchld訊號的概念,接下來利用sigchld訊號編寫**實現父程序對子程序的非同步等待。
1.驗證子程序退出時會給父程序傳送sigchld訊號的機制
**:先建立子程序,然後使其直接退出。再讓父程序呼叫waitpid和signal函式等待子程序並捕捉子程序傳送的17號訊號
執行結果:
結果表明,父程序id為14924的程序確實受到了其子程序退出時傳送的17號訊號。
2.編寫父程序等待子程序的非同步版本
上邊父程序在等待子程序成功後直接退出,現在我們要實現父程序等待子程序成功後,繼續做自己的事情。這就是非同步等待。
**:
在捕捉函式裡加入while迴圈,使得在程式中有多個子程序時,父程序就會一直等待所有子程序退出(id > 0)
先讓父程序執行,5秒之後子程序退出。父程序等待成功後,繼續做自己的事情。
執行結果:
可以看出,情況如預料的那樣。實現了父程序對子程序的非同步等待。
但這裡有乙個問題,如果有子程序一直不退出,那麼父程序就會一直阻塞等待。這顯然是我們不願看到的。所以為了解決這個問題,對捕捉函式handler修改如下:
在上面的**中,對waitpid函式的巨集引數wnohang進行設定,實現非阻塞等待。0和-1都是其可能的返回值,返回0表示沒有子程序可以等,返回-1表示函式呼叫失敗。這樣就避免了父程序的阻塞等待。所以在while迴圈裡再加入了switch選擇分支結構。增強**的健壯性。
再次執行程式,結果依然無誤:
關於linux中的訊號,以後也會有博文介紹,敬請期待。。。
SIGCHLD訊號與父程序非同步等待子程序
阻塞式等待 函式,當然waitpid函式當其第三個引數不為 時也是阻塞式等待。非阻塞式等待 輪詢的方式 當waitpid函式當其第三個引數為 是非阻塞式等待。父程序可以阻塞等待子程序結束,也可以非阻塞地查詢是否有子程序結束等待清理 也就是輪詢的方式 若採用阻塞等待方式,父程序就不能處理自己的工作了 ...
system呼叫與SIGCHLD訊號
很多時候,我們需要通過system這個函式在程式內部來執行系統命令。比如 int rv system mount mnt hgfs 最近有同事發現system呼叫返回 1,但事實上外部命令已成功執行。經調查發現,原來是server在啟動後將自己設定為daemon時,遮蔽了sigchld訊號導致的。在...
SIGCHLD訊號與SIG IGN處理的使用
signal sigchld,sig ign 忽略sigchld訊號,這常用於併發伺服器的效能的乙個技巧 因為併發伺服器常常fork很多子程序,子程序終結之後需要 伺服器程序去wait清理資源。如果將此訊號的處理方式設為 忽略,可讓核心把殭屍子程序轉交給init程序去處理,省去了 大量殭屍程序占用系...