注: wait就是经过包装的waitpid。
static inline pid_t wait(int *wait_stat)
{
return waitpid(-1,wait_stat,0);
}
如果父进程属于守护进程一类,开启TCP套接字等待链接,每当有请求到来,便fork一个子进程传输信息并自由退出。父进程并不关注子进程的退出状态,是否正常都不影响今后的服务,但子进程变成僵尸进程便麻烦了,随着时间的进行,僵尸进程一大堆,虽然占用资源不多,且终究是个隐患。此时可以利用信号处理方式进行非阻塞回收僵死子进程资源。
例子(子进程状态改变会发送SIGCHLD信号给父进程,父进程创建并回收多个子进程):
#include
#include
#include
#include
#include
#include
#include
#include
#define MY_PROCESS_COUNT 10
void child_catch(int signalNumber) {
//子进程状态发生改变时,内核对信号作处理的回调函数
int w_status;
pid_t w_pid;
while ((w_pid = waitpid(-1, &w_status, WNOHANG)) != -1 && w_pid != 0) {
if (WIFEXITED(w_status)) //判断子进程是否正常退出
printf("---catch pid %d,return value %d
", w_pid, WEXITSTATUS(w_status)); //打印子进程PID和子进程返回值
}
}
int main(int argc, char **argv) {
pid_t pid;
int i;
//在此处阻塞SIGCHLD信号,防止信号处理函数尚未注册成功就有子进程结束
sigset_t child_sigset;
sigemptyset(&child_sigset); //将child_sigset每一位都设置为0
sigaddset(&child_sigset, SIGCHLD); //添加SIGCHLD位
sigprocmask(SIG_BLOCK, &child_sigset, NULL); //完成父进程阻塞SIGCHLD的设置
for (i = 0; i < MY_PROCESS_COUNT; i++) {
//创建子进程,创建成功就跳出循环
if ((pid = fork()) == 0)
break;
}
if (MY_PROCESS_COUNT == i) { //括号内为父进程代码
struct sigaction act; //信号回调函数使用的结构体
act.sa_handler = child_catch;
sigemptyset(&(act.sa_mask)); //设置执行信号回调函数时父进程的的信号屏蔽字
act.sa_flags = 0;
sigaction(SIGCHLD, &act, NULL); //给SIGCHLD注册信号处理函数
//解除SIGCHLD信号的阻塞
sigprocmask(SIG_UNBLOCK, &child_sigset, NULL);
printf("im PARENT ,my pid is %d
", getpid());
while (1){ //父进程在这里处理自己的相关事情,同时回收僵死子进程资源
//父进程运行相关代码
}
} else {
//子进程执行代码
printf("im CHILD ,my pid is %d
", getpid());
return i;
}
}
特殊进程
- - 僵尸进程:进程已运行结束,但进程占用的资源未被回收,这样的进程称为僵尸进程。子进程已运行结束,父进程未调用wait或者waitpid函数回收子进程的资源是 子进程变为僵尸进程的原因。
- - 孤儿进程:父进程运行结束,但子进程未运行结束的子进程。(在bash终端上,父进程结束后即会释放终端,子进程其实是在后台运行的。)
- - 守护进程:守护进程是个特殊的孤儿进程,这种进程脱离终端,在后台运行。
exit函数
#include
void exit(int status)
参数:status是返回给父进程的参数(低8位有效)。
注:exit用于在程序运行的过程中随时结束程序,exit的参数是返回给OS的。main函数结束时也会隐式地调用exit函数。exit函数运行时首先会执行由atexit()函数登记的函数,然后会做一些自身的清理工作,同时刷新所有输出流、关闭所有打开的流并且关闭通过标准I/O函数tmpfile()创建的临时文件。exit是结束一个进程,它将删除进程使用的内存空间,同时把错误信息返回父进程;而return是返回函数值并退出函数。通常情况:exit(0)表示程序正常, exit(1)和exit(-1)表示程序异常退出,exit(2)表示表示系统找不到指定的文件。在整个程序中,只要调用exit就结束(当前进程或者在main时候为整个程序)。
_exit函数
#include
void _exit(int status)
参数:status是返回给父进程的参数(低8位有效)。