一、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位置:
/HymanLiuTS/NetDevelopment
克隆本项目:
Gitclone git@:HymanLiuTS/NetDevelopment.git
获取本文源代码:
git checkout NL32
---------------------
作者:HymanLiuTS
来源:CSDN
原文:/hyman_c/article/details/53512999
版权声明:本文为博主原创文章,转载请附上博文链接!