1. 原理
1、子進程在退出時,會給父進程發送17號信號 SIGCHLD
2、可以對信號SIGCHLD進行自定義動作,執行handler
3、handler是系統回調函數,在收到該信號後,在進程又內核返回用戶態前,處理自定義函數handler。
2、異步等待子進程
void handler(int sig)
{
pid_t ret = waitpid(-1,NULL,WNOHANG);
printf("get a sig:%d\n",sig);
printf("wait a id: %d\n",ret);
}
int main()
{
signal(SIGCHLD, handler);
pid_t id = fork();
if(id < 0)
perror("fork");
else if(id == 0){//child
printf("i am child: %d\n",getpid());
sleep(4);
printf("id: %d child quit! \n",getpid());
exit(1);
}
else{//father
while(1){
sleep(1);
printf("i am father:%d\n",getpid());
}
}
return 0;
}
我們可以看到,已經實現了單個子進程異步等待的方式,但當我們多個進程退出時,不知道這個代碼還可以嗎??
void handler(int sig)
{
pid_t ret = waitpid(-1,NULL,WNOHANG);
printf("get a sig:%d\n",sig);
printf("wait a id: %d\n",ret);
}
int main()
{
signal(SIGCHLD, handler);
pid_t id = fork();
if(id < 0)
perror("fork");
else if(id == 0)
{//child
printf("i am child 1: %d\n",getpid());
sleep(2);
printf("id: %d child quit! \n",getpid());
exit(1);
}
else
{//father
if(fork() == 0){//再創建了一個子進程
printf("i am child 2: %d\n",getpid());
sleep(5);
printf("id: %d child quit! \n",getpid());
exit(2);
}
while(1){
sleep(1);
printf("i am father:%d\n",getpid());
}
}
return 0;
}
看到上面的結果,貌似已經實現了可以等待多個子進程,其實不然,如果出現了:在進程從內核返回用戶態前有多個子進程退出了,而系統只會調用handler一次。
如果我們把讓代碼的兩個子進程的sleep時間都寫成4秒結果就有變成了:
要處理這種情況,我們只需要加入循環:(更改handler代碼):
void handler(int sig)
{
printf("get a sig:%d\n",sig);
pid_t ret;
do{
ret = waitpid(-1,NULL,WNOHANG);
if(ret > 0){
printf("wait a id: %d\n",ret);
}
}while(ret > 0);
}