SIGCHLD:子進程在終止退出時會給父進程發SIGCHLD信號,該信號的默認處理動作是忽略。
驗證如下:創建一個子進程,自定義信號SIGCHLD的捕捉函數,若子進程退出並調用了此信號捕捉函數,則驗證成功。
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
void myhander(int sig)
{
printf("father get child sig,child exit, sig##%d\n",sig);
}
int main()
{
signal(SIGCHLD,myhander);
pid_t id=fork();
if(id==0) //child
{
printf("child is doing something:child pid##%d\n",getpid());
sleep(1);
exit(1); //子進程退出
}
//驗證是否發信號SIGCHLD,執行myhander函數
pid_t ret=waitpid(id,NULL,0); //阻塞等待子進程
if(ret>0)
{
printf("wait success!!!child pid##%d\n",ret);
}
return 0;
}
結果如下:驗證成功
子進程異步等待方式:
用wait和waitpid函數清理殭屍進程,父進程可以阻塞等待子進程結束,也可以非阻塞地查詢是否有子進程結束等待清理(也就是輪詢的方式)。採用第一種方式,父進程阻塞了就不能處理自己的工作了;採用第二種方式,父進程在處理自己的工作的同時還要記得不時地輪詢一 下,程序實現複雜。
所以由上可知父進程可以自定義SIGCHLD信號的處理函數,這樣父進程只需專心處理自己的工作,不必關心子進程了,子進程終止時會發信號通知父進程,父進程在信號處理函數中調用wait清理子進程即可。
代碼如下:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
void myhander(int sig) //每個子進程退出發送信號進入此函數
{
printf("father get child sig,child exit: sig##%d\n",sig);
pid_t id;
while((id=waitpid(-1,NULL,WNOHANG))>0) //父進程非阻塞等待當前任意退出的子進程
{
printf("wait success!!! child pid##%d\n",id);
}
}
int main()
{
signal(SIGCHLD,myhander); //註冊信號處理函數
pid_t id1=fork(); //創建子進程1
if(id1==0) //child
{
printf("child is doing something:child1 pid##%d\n",getpid());
exit(1); //運行完退出
}
pid_t id2=fork(); //創建子進程2
if(id2==0) //child
{
printf("child is doing something:child2 pid##%d\n",getpid());
sleep(2);
exit(-1); //2s後異常退出
}
while(1) //父進程每1s打印一次
{
printf("father is doing something!!!\n");
sleep(1);
}
return 0;
}
以上代碼中創建兩個子進程第一個直接退出,第二個等待2S退出,則在它們各自退出時間發送信號給父進程,父進程則在各自退出時間執行SIGCHLD信號捕捉函數,等待成功後,若當前暫時再沒有了退出的子進程,其則不阻塞等待而去執行自己的工作。
如下結果: