网络编程(32)—— linux中销毁僵尸进程的四种方法
一、wait函數
函數原型:
pid_t wait(int *status);
描述:
wait可以回收任意一個僵尸進程,只要系統中存在僵尸進程,調用一次wait,就會回收一個僵尸進程。
參數說明:
??status - 當子進程結束之后,其進入僵尸進程狀態。其狀態變化信息被操作系統放置在內存中某一處位置,而status就是這處位置的指針,通過調用wait函數可以獲取這部分位置的數據。
獲取到數據之后,通過一系列宏可以獲取目前操作系統的狀態。如:
WIFEXITED(*status)可以判斷該進程是否正常結束(main函數通過return或者exit結束),若正常結束返回true,否則返回false。
WEXITSTATUS(*status)用來獲取進程正常結束時main函數的返回值,前提是WIFEXITED(status)返回true。
返回值:
返回被結束僵尸狀態進程的進程ID。
舉例:
int main()
{
?? ?pid_t pid;
?? ?int status;
?? ?pid=fork();
?? ?if(pid==0)
?? ?{
?? ??? ?exit(10);
?? ?}
?? ?else
?? ?{
?? ??? ?pid = wait(&status);
?? ??? ?if(WIFEXITED(status))
?? ??? ?{
?? ??? ??? ?printf("process %d exited,return value = %d\n",pid,WEXITSTATUS(status));
?? ??? ?}
?? ?}
?? ?return 0;
}
缺點:
wait()函數為阻塞函數,也就是說如果操作系統中無僵尸進程的話,程序會一直在wait()處等待,直到出現僵尸進程。
二、waitpid函數
函數原型:
pid_t waitpid(pid_t pid, int *status, int options);
描述:
waitpid()也是用來回收一個僵尸進程,與wait()不同的是,它是非阻塞函數,可以通過設置pid參數回收指定進程ID的僵尸進程,也可以指定回收任意僵尸進程。
參數說明:
status,和wait()函數相同。
pid,指定要回收進程的進程ID,若設為-1,則默認回收任意一個僵尸進程。
options,設置選項,一般情況下設置成WNOHANG,表示不阻塞。
返回值
若存在僵尸進程,返回被結束僵尸狀態進程的進程ID;若不存在僵尸進程返回0;若發生錯誤,返回-1.
舉例:
int main()
{
?? ?pid_t pid;
?? ?int status;
?? ?pid=fork();
?? ?if(pid==0)
?? ?{
?? ??? ?sleep(10);
?? ??? ?exit(10);
?? ?}
?? ?else
?? ?{
?? ??? ?while((pid=waitpid(-1,&status,WNOHANG))==0)
?? ??? ?{
?? ??? ??? ?puts("wating ...");
?? ??? ??? ?sleep(2);
?? ??? ?}
?? ??? ?if(WIFEXITED(status))
?? ??? ?{
?? ??? ??? ?printf("process %d exited,return value = %d\n",pid,WEXITSTATUS(status));
?? ??? ?}
?? ?}
?? ?return 0;
}
缺點:
雖然waitpid()不是阻塞函數,但是使用時需要在循環中使用,只有在回收完僵尸進程后才會執行循環之后的代碼。
三 signal函數
函數原型:
sighandler_t signal(int signum, sighandler_t handler);
描述:
系統級別的api,向操作系統注冊信號和信號處理函數,當操作系統捕獲到注冊的信號時會調用該信號處理函數。
參數:
signum,向操作系統注冊的信號,子進程結束的信號是SIGCHLD。
handler,信號的處理函數,函數原型一般是void handler(int sig)的形式,函數的參數為操作系統捕獲的信號,函數的返回值是void
返回值:
返回之前注冊的處理該信號的信號處理函數的函數指針。
舉例:
void sig_handling(int sig)
{
?? ?int status;
?? ?pid_t pid;
?? ?if(sig==SIGCHLD)
?? ?{
?? ??? ?pid = waitpid(-1,&status,WNOHANG);
?? ??? ?if(WIFEXITED(status))
?? ??? ?{
?? ??? ??? ?printf("process %d exited,return value=%d\n",pid,WEXITSTATUS(status));
?? ??? ?}
?? ?}
}
?
?
int main()
{
?? ?pid_t pid;
?? ?signal(SIGCHLD,sig_handling);
?? ?pid=fork();
?? ?if(pid==0)
?? ?{
?? ??? ?exit(11);
?? ?}
?? ?else
?? ?{
?? ??? ?sleep(10000);
?? ?}
?? ?return 0;
}
??請注意:
??1、在信號處理函數sig_handling中,也需要用waitpid()來回收僵尸進程,也就是說signal只是一個注冊信號的作用,其本身并沒有回收僵尸進程的功能。
??2、一旦用signal注冊了信號和信號處理函數,一旦發生該信號,會結束進程的sleep()狀態,也就是說在父進程的sleep(10000);將會被打斷,不會真的睡10000秒。
?
四 sigaction函數
函數原型:
int sigaction(int signum, const struct sigaction *act,
?????????????????????struct sigaction *oldact);
描述:
signum,和signal一樣,表示需要注冊的信號。
act,sigaction類型的指針,sigaction類型的定義如下:
struct sigaction {
???????????????void ????(*sa_handler)(int);
???????????????void ????(*sa_sigaction)(int, siginfo_t *, void *);
???????????????sigset_t ??sa_mask;
???????????????int ???????sa_flags;
???????????????void ????(*sa_restorer)(void);
???????????};
??我們進行使用時,只需填寫其sa_handler、sa_mask、sa_flags三個成員,sa_handler為信號處理函數,sa_mask使用sigemptyset()函數進行置空,sa_flags直接賦為0。
??oldact,之前注冊的?sigaction 類型的指針。
返回值:
??成功返回0,失敗返回-1
舉例:
void sig_handling(int sig)
{
?? ?int status;
?? ?pid_t pid;
?? ?if(sig==SIGCHLD)
?? ?{
?? ??? ?pid = waitpid(-1,&status,WNOHANG);
?? ??? ?if(WIFEXITED(status))
?? ??? ?{
?? ??? ??? ?printf("process %d exited,return value=%d\n",pid,WEXITSTATUS(status));
?? ??? ?}
?? ?}
}
?
?
int main()
{
?? ?pid_t pid;
?? ?struct sigaction act;
?? ?act.sa_handler=sig_handling;
?? ?sigemptyset(&act.sa_mask);
?? ?act.sa_flags=0;
?? ?sigaction(SIGCHLD,&act,0);
?? ?pid=fork();
?? ?if(pid==0)
?? ?{
?? ??? ?exit(11);
?? ?}
?? ?else
?? ?{
?? ??? ?sleep(10000);
?? ?}
?? ?return 0;
}
??與signal相比,sigaction函數雖然比較繁瑣,但是他的長處在于linux系統多版本的兼容性,而部分版本linux是不支持signal函數的,因此在實際的使用中sigaction的使用范圍更廣。
Github位置:
https://github.com/HymanLiuTS/NetDevelopment
克隆本項目:
Git?clone git@github.com:HymanLiuTS/NetDevelopment.git
獲取本文源代碼:
git checkout NL32
---------------------?
作者:HymanLiuTS?
來源:CSDN?
原文:https://blog.csdn.net/hyman_c/article/details/53512999?
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
總結
以上是生活随笔為你收集整理的网络编程(32)—— linux中销毁僵尸进程的四种方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 理解tcp关闭连接中的time_wait
- 下一篇: Ansible中文权威指南