1.进程退出函数
进程退出分为正常退出&异常退出
正常退出:
1、main函数调用return
2、进程调用exit(),标准c库
3、进程调用_exit()或者_Exit(),属于系统调用
补充
1、进程最后一个线程返回
2、最后一个线程调用pthread_exit
异常退出:
1、调用abort,等于放弃当前进程
2、当进程收到某些信号时,如ctrl+c
3、最后一个线程对取消(cancellatio)请求做出响应
exit函数:
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
代码:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt=0;
pid=vfork();
if(pid>0){
while(1){
printf("cnt=%d\n",cnt);
printf("this is father print%d\n",getpid());
sleep(1);
}
}
if(pid==0){
while(1){
printf("this is child print,pid=%d\n",getpid());
sleep(1);
cnt++;
if(cnt==3){
//break;
//exit(0);
//_exit(0);
_Exit(0);
}
}
}
return 0;
}
进程退出调用(exit\_exit\_Exit)函数,尽量调用exit函数,调用后会对子进程调用的数据进行一下冲刷处理再退出,_exit\_Exit是直接退出。
结果:
2.父子进程退出
僵尸进程:子进程退出状态不被收集,变成僵尸进程(僵死进程)Z+状态
孤儿进程:父进程退出,子进程还在运行;此时父进程会被init进程吸收,其pid=1;Linux系统作用
调用wait()阻塞函数:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
作用:等待子进程完成或者退出,之后通常运行父进程
进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。
参数:
参数status(注意此为指针)用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL,就像这样:pid = wait(NULL);
返回值:
如果成功,wait会返回被收集的子进程的进程ID;
如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。
多数使用wait函数
2.waitpid函数: wait使调用者阻塞,waitpid有一个选项,可以使调用者不阻塞。
#include <sys/wait.h>
#include <sys/types.h>
pid_t waitpid(pid_t pid, int *status, int options)
参数
status:与wait的一样用法。
pid:从参数的名字pid和类型pid_t中就可以看出,这里需要的是一个进程ID。但当pid取不同的值时,在这里有不同的意义。
对于waitpid函数中pid参数作用解释如下:
pid=-1 等待任一子进程,&wait等效
pid>0 等待其进程ID与pid相等的子进程
pid==0 等待其组ID等于调用进程组ID的任一子进程
pid<-1 等待其组ID等于pid绝对值的任一子进程
options:提供了一些额外的选项来控制waitpid,目前在Linux中只支持:WNOHANG和WUNTRACED两个选项,这是两个常数,可以用"|"运算符把它们连接起来使用;比如ret=waitpid(-1,NULL,WNOHANG | WUNTRACED); 如果我们不想使用它们,也可以把options设为0,如ret=waitpid(-1,NULL,0); 如果使用了WNOHANG参数调用waitpid,即使没有子进程退出,它也会立即返回,不会像wait那样永远等下去。而WUNTRACED参数,由于涉及到一些跟踪调试方面的知识,加之极少用到,可以自行查阅相关材料。
返回值:waitpid的返回值比wait稍微复杂一些,一共有三种情况:
① 当正常返回的时候,waitpid返回收集到的子进程的进程ID;
② 如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0; 一般options写WNOHANG
③ 如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid就会出错返回,这时errno被设置为ECHILD;
waitpid提供了wait函数不能实现的3个功能:
① waitpid等待特定的子进程, 而wait则返回任一终止状态的子进程;
② waitpid提供了一个wait的非阻塞版本;
③ waitpid支持作业控制。用于检查 wait() 和 waitpid() 两个函数返回终止状态的宏: 这两个函数返回的子进程状态都保存在status指针中,用以下3个宏可以检查该状态:
WIFEXITED(status): 若为正常终止, 则为真。此时可执行 WEXITSTATUS(status): 取子进程传送给exit或_exit参数的低8位.
WIFSIGNALED(status): 若为异常终止, 则为真。此时可执行 WTERMSIG(status): 取使子进程终止的信号编号.
WIFSTOPPED(status): 若为当前暂停子进程, 则为真。此时可执行 WSTOPSIG(status): 取使子进程暂停的信号编号
代码:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t pid;
int cnt=0;
int status=10;
pid=fork();
if(pid>0){
// wait(&status);
waitpid(pid,&status,WNOHANG);
printf("child quit,child status=%d\n",WEXITSTATUS(status));
while(1){
printf("cnt=%d\n",cnt);
printf("this is father print%d\n",getpid());
sleep(1);
}
}
if(pid==0){
while(1){
printf("this is child print,pid=%d\n",getpid());
sleep(1);
cnt++;
if(cnt==3){
//break;
//exit(0);
//_exit(0);
exit(3);
}
}
}
return 0;
}
运行:
子进程、父进程同时运行3次,子进程退出,父进程运行;非阻塞下,子进程变成僵尸进程