waitpid() “假“信號排隊

實現對子進程的回收,以及回收狀態的打印

#include<stdio.h>

#include<unistd.h>

#include<error.h>

#include<sys/types.h>

#include<stdlib.h>

#include<sys/wait.h>

#include<signal.h>


voidsys_err(char *errmes,int errno){


perror(errmes);

exit(errno);

}


voiddo_sigchild(int signum){

pid_tpid;

intstatus;


sleep(2);

while((pid=waitpid(0,&status,WNOHANG))>0){

if(WIFEXITED(status)){

printf("child%d is exit %d\n",pid,status);

}elseif(WIFSIGNALED(status)){

printf("child%d id exit %d\n",pid,WTERMSIG(status));

}

}



}

intmain(void){


pid_tpid;

inti=0;

intn=10;

structsigaction act;


act.sa_handler=do_sigchild;

sigemptyset(&act.sa_mask);

act.sa_flags=0;


sigaction(SIGCHLD,&act,NULL);


while(i<10){

pid=fork();

i++;

if(pid==0){

break;

}elseif(pid<0){

sys_err("fork",-1);

}

}

if(pid==0){

while(n--){

printf("Itis chid,pid=%d\n",getpid());

sleep(1);

}

}elseif(pid>0){

while(1){

printf("Itis parent,pid=%d\n",getpid());

sleep(1);

}

}



return0;

}


輸出結果:

It is chid,pid=6805
child 6796 is exit 0
child 6797 is exit 0
child 6798 is exit 0
child 6799 is exit 0
child 6800 is exit 0
child 6801 is exit 0
child 6802 is exit 0
child 6803 is exit 0
child 6804 is exit 0
child 6805 is exit 0
It is parent,pid=6795

在上面的函數中,需要討論的問題是:

Linux是不支持信號排隊的,爲什麼這裏就算有多個子進程發出SIGCHLD信號,也不會被忽視?

   第一點,這裏還要回到信號集的問題上,當信號開始被處理的時候,未決集就已經翻轉了(這時候,handler可能還在執行中),所以,可以接收下一個信號,也就是下一個信號已經保存進來了,這裏子進程同時發信號,這個同時是個假的同時,因爲內核處理進程終究還是時間差的。

  第二點,函數的可重入性,關於什麼是可重入函數,什麼是不可重入函數:

不可重入函數:函數執行中不能被打斷再執行當前函數,打斷之後,再執行,第一次調用的不能實現預期的效果

可重入函數:函數被打斷,再調用當前函數,原來的函數還是會實現預期的效果

在信號捕捉函數中禁止調用不可重入函數,也就是在捕捉函數中,只能調用可重入的系統函數,以保證運行結果的安全性

也就是waitpid()是可重入函數,這一點很重要

     處理信號的關鍵點:1.信號接收到2.信號未被阻塞3.可進入處理函數

    所以從上面就可以分析出來,子進程結束以後,由於未決集的翻轉的特點,以及waitpid()的可重入性,就實現了“假信號排隊”的現象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章