【linux高级程序设计】(第八章)进程管理与程序开发 3
回收进程用户空间资源
仅调用退出函数的进程属于一个僵死进程,没有释放进程控制块PCB。
void exit (int __status):退出进程。会以反序执行on_exit()和atexit()中注册的清理函数,刷新流缓冲区。执行成功没有返回值,参数status用来标识退出状态返回给父进程;否则返回-1。
void _exit (int __status):不调用任何祖册函数和直接退出进程。此函数调用后不会返回,而是传递SIGCHLD信号给父进程,父进程可以通过wait函数获得子进程结束的状态。该函数不处理标准I/O缓冲区
int atexit (void (*__func) (void)):告诉进程,在正常退出时执行注册的func函数。注册函数没有参数
int on_exit (void (*__func) (int __status, void *__arg), void *__arg):告诉进程,在正常退出时执行注册的func函数。注册函数有参数,第一个参数为退出的状态,第二个参数为用户的输入信息。
exit与return区别:
(1)return退出当前函数,exit()退出当前进程。在main函数中return(0)和exit(0)完成一样的功能。
(2)return仅从子函数中返回,并不退出进程。而exit()在子函数中会调用终止处理程序,关闭所有I/O流。
#include<stdio.h> #include<unistd.h> #include<string.h> int test(void) { printf("a\n"); sleep(1); //exit(0); //循环只执行一次 return 0; //死循环 } int main(int argc, char * argv[]) { int i = 0; i++; printf("i=%d\n",i); while(1) test(); return 0; }
exit与_exit使用对比
#include<stdlib.h> int main(int argc, char * argv[]) { printf("output\n"); printf("content in buffer"); //注意没有回车,在缓冲区 _exit(0); }
_exit(0)只显示output
#include<stdlib.h> int main(int argc, char * argv[]) { printf("output\n"); printf("content in buffer"); //注意没有回车,在缓冲区 exit(0); }
exit(0)显示output和content in buffer
on_exit使用例子:
#include<stdlib.h> void test_exit(int status, void *arg) { printf("before exit()!\n"); printf("exit %d\n", status); printf("arg=%s\n",(char*)arg); } int main() { char *str="test"; on_exit(test_exit,(void *)str); exit(4321); }
回收内核空间资源
进程PCB的释放,由当前进程的父进程完成的。父进程可以显示的调用wait()和waitpid()函数来完成。
__pid_t wait (__WAIT_STATUS __stat_loc):父进程阻塞式的等待该进程的任意一个子进程结束,回收子进程的内核进程资源。返回当前结束子进程的PID,退出状态存储在stat_loc中。
#define WIFSIGNALED(status) __WIFSIGNALED(__WAIT_INT(status)) :宏,用来判断进程是否是因为收到信号后而退出的。如果是宏值为1.
#define WIFEXITED(status) __WIFEXITED(__WAIT_INT(status)):宏,用来判断进程是否是正常退出的。如果是,宏值为1.
#include<stdio.h> #include<unistd.h> #include<sys/types.h> #include<fcntl.h> #include<string.h> #include<stdlib.h> extern int errno; int main(int argc, char *argv[]) { pid_t pid_one, pid_wait; int status; if((pid_one = fork()) == -1) perror("fork"); if(pid_one == 0) { printf("my pid is %d\n", getpid()); sleep(20); exit(EXIT_SUCCESS); //正常退出 } else { pid_wait = wait(&status); //等待子进程结束 if(WIFEXITED(status)) printf("wait on pid: %d, normal exit, return value is:%4x\n",pid_wait, WEXITSTATUS(status)); else if(WIFSIGNALED(status)) printf("wait on pid:%d, recive signal, return value is:%4x\n", pid_wait, WIFSIGNALED(status)); } return 0; }
__pid_t waitpid (__pid_t __pid, int * __stat_loc, int __options):等待指定子进程结束
第一个参数为进程PID值。
PID > 0 :表示等待进程的PID就是PID
PID == -1 :表示等待任意子进程结束,相当于调用wait函数
PID == 0 :表示等待与当前进程的进程组PGID一致的进程结束
PID < -1 :表示等待进程组PGID是此值的绝对值的进程结束
第二个参数为结束进程的结束状态。
第三个参数为等待选项,可设置为
0 :阻塞
WNOHANG 1 :不阻塞等待 没有子进程退出将返回0, 否则返回子进程的PID。
WUNTRACED 2 :报告状态信息
孤儿进程与僵死进程
孤儿进程:父进程先退出,导致子进程被init进程收养的进程为孤儿进程。即父进程更改为init,init进程负责在孤儿进程退出后回收他的内核空间资源。
僵死进程:进程已经退出,但是父进程还没有回收其内核空间资源PCB
#include<stdio.h> #include<unistd.h> #include<stdlib.h> int main() { pid_t pid; if((pid = fork()) == -1) perror("fork"); else if(pid == 0) { printf("child_pid pid = %d\n", getpid()); } sleep(3); system("ps"); exit(0); }
此时1184为僵死进程。