网络编程(32)—— linux中销毁僵尸进程的四种方法
一、wait函數(shù)
函數(shù)原型:
pid_t wait(int *status);
描述:
wait可以回收任意一個僵尸進程,只要系統(tǒng)中存在僵尸進程,調(diào)用一次wait,就會回收一個僵尸進程。
參數(shù)說明:
??status - 當子進程結(jié)束之后,其進入僵尸進程狀態(tài)。其狀態(tài)變化信息被操作系統(tǒng)放置在內(nèi)存中某一處位置,而status就是這處位置的指針,通過調(diào)用wait函數(shù)可以獲取這部分位置的數(shù)據(jù)。
獲取到數(shù)據(jù)之后,通過一系列宏可以獲取目前操作系統(tǒng)的狀態(tài)。如:
WIFEXITED(*status)可以判斷該進程是否正常結(jié)束(main函數(shù)通過return或者exit結(jié)束),若正常結(jié)束返回true,否則返回false。
WEXITSTATUS(*status)用來獲取進程正常結(jié)束時main函數(shù)的返回值,前提是WIFEXITED(status)返回true。
返回值:
返回被結(jié)束僵尸狀態(tài)進程的進程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()函數(shù)為阻塞函數(shù),也就是說如果操作系統(tǒng)中無僵尸進程的話,程序會一直在wait()處等待,直到出現(xiàn)僵尸進程。
二、waitpid函數(shù)
函數(shù)原型:
pid_t waitpid(pid_t pid, int *status, int options);
描述:
waitpid()也是用來回收一個僵尸進程,與wait()不同的是,它是非阻塞函數(shù),可以通過設置pid參數(shù)回收指定進程ID的僵尸進程,也可以指定回收任意僵尸進程。
參數(shù)說明:
status,和wait()函數(shù)相同。
pid,指定要回收進程的進程ID,若設為-1,則默認回收任意一個僵尸進程。
options,設置選項,一般情況下設置成WNOHANG,表示不阻塞。
返回值
若存在僵尸進程,返回被結(jié)束僵尸狀態(tài)進程的進程ID;若不存在僵尸進程返回0;若發(fā)生錯誤,返回-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()不是阻塞函數(shù),但是使用時需要在循環(huán)中使用,只有在回收完僵尸進程后才會執(zhí)行循環(huán)之后的代碼。
三 signal函數(shù)
函數(shù)原型:
sighandler_t signal(int signum, sighandler_t handler);
描述:
系統(tǒng)級別的api,向操作系統(tǒng)注冊信號和信號處理函數(shù),當操作系統(tǒng)捕獲到注冊的信號時會調(diào)用該信號處理函數(shù)。
參數(shù):
signum,向操作系統(tǒng)注冊的信號,子進程結(jié)束的信號是SIGCHLD。
handler,信號的處理函數(shù),函數(shù)原型一般是void handler(int sig)的形式,函數(shù)的參數(shù)為操作系統(tǒng)捕獲的信號,函數(shù)的返回值是void
返回值:
返回之前注冊的處理該信號的信號處理函數(shù)的函數(shù)指針。
舉例:
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、在信號處理函數(shù)sig_handling中,也需要用waitpid()來回收僵尸進程,也就是說signal只是一個注冊信號的作用,其本身并沒有回收僵尸進程的功能。
??2、一旦用signal注冊了信號和信號處理函數(shù),一旦發(fā)生該信號,會結(jié)束進程的sleep()狀態(tài),也就是說在父進程的sleep(10000);將會被打斷,不會真的睡10000秒。
?
四 sigaction函數(shù)
函數(shù)原型:
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為信號處理函數(shù),sa_mask使用sigemptyset()函數(shù)進行置空,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函數(shù)雖然比較繁瑣,但是他的長處在于linux系統(tǒng)多版本的兼容性,而部分版本linux是不支持signal函數(shù)的,因此在實際的使用中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?
版權聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!
總結(jié)
以上是生活随笔為你收集整理的网络编程(32)—— linux中销毁僵尸进程的四种方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 理解tcp关闭连接中的time_wait
- 下一篇: 深入理解Linux IO复用之epoll