进程终止
有3种正常终止方法、2中异常终止方法。
正常终止:
1 main函数内执行return语句。
2 调用exit函数,其操作包括调用各终止处理程序(调用atexit时登记),关闭所有标准IO流。(exit用于结束正在运行的整个程序,它将参数返回给OS,把控制权交给操作系统;而return 是退出当前函数,返回函数值,把控制权交给调用函数)
3 调用_exit系统调用函数。exit函数也调用此函数。
异常终止:
1 调用abort函数,产生SIGABRT信号。
2 进程接收到某个信号而终止。进程本身如调用abort函数、其他进程和内核都能产生转送到某一进程的信号。例如进程越出其地址空间访问存储单元,或者除以0,内核就会为该进程产生相应的信号。
不管进程如何终止,最后都会执行内核中的一段代码,它为相应进程关闭所有打开的描述符,释放进程所使用的存储器等。
我们希望终止进程能够通知其父进程它是怎么终止的,对于exit和_exit函数,这依靠传递给它的退出状态(exit status)参数来实现。
在异常终止情况,内核(而非进程)产生一个指示其异常终止原因的终止状态。
孤儿进程与僵死进程:
如果父进程在子进程之前终止,子进程变为孤儿进程,那么子进程的父进程都改变为init进程,有init进程领养。实现方法:进程即将终止时,内核遍历检查所有活动进程,判断它是否正要终止的进程的子进程,若是则将其父进程ID改为1,即init进程ID。一旦子进程终止,init进程调用wait函数取得其终止状态。
如果子进程在父进程之前终止,父进程如何得到子进程的终止状态?由于内核为每个终止进程都保存了信息,所以父进程调用wait和waitpid函数可以得到这些信息,包括进程ID,终止状态,以及cpu使用时间总量。
如果父进程未调用wait / waitpid,对终止的子进程进行善后处理,那么这些子进程成为僵死进程,那么保留的那段信息就不会释放,其进程号一直被占用,但系统能用的进程号有限,如果大量产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。
解决方法:
把产生大量僵死进程的那个父进程杀掉(通过kill发送SIGTERM或者SIGKILL信号),它产生的僵死进程就变成了孤儿进程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源。
具体方法
(1)SIGCHILD信号
#include<stdlib.h> #include<unistd.h> #include<errno.h> #include<signal.h> #include<stdio.h> static void SIGCHLD_process(int signo); int main() { pid_t pid; if((pid=fork())<0){ printf("fork error\n"); } if(signal(SIGCHLD,SIGCHLD_process)==SIG_ERR) printf("signal error"),exit(1); if(pid==0){ printf("child process id %d\n",getpid()); exit(0); } printf("father process id %d will sleep 2s\n",getpid()); sleep(2); system("ps -o pid,ppid,state,tty,command"); exit(0); } void SIGCHLD_process(int signo){ pid_t pid; while((pid=wait(NULL))>0) printf("child process %d terminal\n",pid); }
(2)fork两次
原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程。
#include<unistd.h> #include<stdlib.h> #include<sys/types.h> #include<sys/wait.h> int main(){ pid_t pid; if((pid=fork())<0){ printf("fork error\n"); exit(1); } else if(pid==0){//first child if( (pid=fork())<0){ printf("fork error\n"); exit(0); } else if(pid>0){ printf("first child id %d exit",getpid()); exit(0);//parent from second fork ==first child exit } sleep(2);//sleep for 2s waitfor parent exit printf("second child id %d ,parent id %d\n",getpid(),getppid()); exit(0); } if(waitpid(pid,NULL,0)!=pid){//wait for first child printf("waitpid error\n"); exit(1); } system("ps -o pid,ppid,state,tty,command"); exit(0); }