进程的退出
returen 和 exit,return 只是函数的返回,而 exit 却是进程的结束。
void exit(int status);
#include <stdlib.h>void exit(int status);功能:终止进程参数:status:退出状态码。status&0377的值给父进程。返回值:永远不返回。
代码示例
- test.c
#include <stdio.h>#include <stdlib.h>int main(void){ getchar(); exit(-1);}
注册进程结束调用函数
在进程结束前,可以注册一些函数给进程,在进程结束时会自动调用这些被注册的函数。
on_exit(3)
#include <stdlib.h>int on_exit(void (*function)(int , void *), void *arg);功能:注册一个函数给进程,在进程终止的时候调用该函数参数:function:指定退出函数的名字void (*function)(int , void *)arg:指定退出函数的第二个参数返回值:0 成功非0 错误
代码示例(on_exit)
- on_exit.c
#include <stdio.h>#include <stdlib.h>void doit(int n,void *arg){ printf("n=%dtarg:%sn", n,(char *)arg); return;}int main(void){ //向进程注册退出函数 on_exit(doit,"beijing"); getchar(); exit(3);}
atexit
atexit(3)
#include <stdlib.h>int atexit(void (*function)(void));功能:注册一个函数给进程,在进程终止的时候调用该函数参数:function:指定了要注册的函数的名字返回值:0 成功非0 错误
代码示例(atexit)
- atexit.c
#include <stdio.h>#include <stdlib.h>//注册给进程的退出函数void doit(void){ printf("hahha....n"); return;}int main(void){ //向进程注册一个退出处理函数 atexit(doit); getchar(); return 0;}
进程资源的回收
在进程退出后,父进程会回收子进程的资源。
使用 wait(2)、waitpid(2) 系统调用回收子进程的资源。
如果父进程早于子进程结束,那么父进程的子进程的父亲就改变成为 init 进程,这种进程被成为孤儿进程。
代码示例
- lonely.c
#include <stdio.h>#include <unistd.h>#include <stdlib.h>int main(void){ pid_t pid; //创建子进程 pid=fork(); if(pid==-1){ perror("fork"); return 1; } if(pid==0){//子进程的代码 sleep(5); printf("child...n"); //getchar(); exit(0); }else{//父进程的代码 printf("parent...n"); exit(0); } return 0;}
- 执行结果
wait 回收进程资源
#include <sys/types.h>#include <sys/wait.h>pid_t wait(int *status);功能:等待进程改变状态。参数:status:退出状态码的地址。子进程的退出状态存放在这块地址空间里。可以使用一些宏检测退出原因。WIFEXITED(status) 如果正常死亡,返回真WEXITSTATUS(status) 返回子进程的退出状态和0377的与,那个值。WIFSIGNALED(status) 如果子进程被信号终止,返回真WTERMSIG(status) 检测被几号信号终止。只有上个宏为真的时候,才使用。返回值:-1 错误返回终止的子进程的pid
代码示例
- wait.c
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/wait.h>int main(void){ pid_t pid; int s; //创建子进程 pid=fork(); if(pid==-1){ perror("fork"); return 1; } if(pid==0){ printf("child pid=%dn", getpid()); //sleep(5); getchar(); exit(-1); }else{ //等待子进程的结束 wait(&s); if(WIFEXITED(s)){ //子进程正常终止 printf("status:%dn", WEXITSTATUS(s)); } //检测子进程是否被信号终止 if(WIFSIGNALED(s)){ //输出终止子进程的信号编号 printf("signum :%dn", WTERMSIG(s)); } printf("parent...n"); } return 0;}
- 执行结果
waitpid
pid_t waitpid(pid_t pid,int *status,int options);
功能:等待进程改变状态。参数:pid:< -1: pid取绝对值,如果子进程的组id等于这个绝对值,那么这个子进程就被等待。-1:等待任意子进程0:等待和当前进程有同一个组id的子进程> 0 等待子进程的pid是pid参数的子进程。status:同wait(2)参数的使用options:WNOHANG:非阻塞回收。0 阻塞回收返回值:-1 错误 0 没有子进程退出回收的子进程的pid
代码示例
- waitpid.c
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/wait.h>int main(void){ pid_t pid; int s; //创建子进程 pid=fork(); if(pid==-1){ perror("fork"); return 1; } if(pid==0){ printf("child pid=%dn", getpid()); //sleep(5); getchar(); exit(-1); }else{ //非阻塞等待子进程的结束 waitpid(-1,&s,WNOHANG); if(WIFEXITED(s)){ //子进程正常终止 printf("status:%dn", WEXITSTATUS(s)); } //检测子进程是否被信号终止 if(WIFSIGNALED(s)){ //输出终止子进程的信号编号 printf("signum :%dn", WTERMSIG(s)); } printf("parent...n"); } return 0;}
- 执行结果
给指定进程发送信号(kill)
kill -[信号编号] [进程的pid]
僵尸进程
子进程已经终止,但是父进程还没有回收子进程的资源,这时候的子进程处于僵尸状态,成为僵尸进程。
代码示例
- zombile.c
#include <stdio.h>#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <stdlib.h>int main(void){ pid_t pid; pid=fork(); if(pid==-1){ perror("fork"); return 1; } if(pid==0){ exit(0); }else{ sleep(20); wait(NULL); } return 0;}
在进程的虚拟地址空间加载新的映像
在子进程的虚拟地址空间加载新的影像,需要使用系统提供的一个家族的函数。
execl(3)
#include <unistd.h>extern char **environ;int execl(const char *path, const char *arg, ...);int execlp(const char *file, const char *arg, ...);int execle(const char *path, const char *arg, ..., char * const envp[]);int execv(const char *path, char *const argv[]);int execvp(const char *file, char *const argv[]);int execvpe(const char *file, char *const argv[], char *const envp[]);
execve(2)
#include <unistd.h>int execve(const char *filename, char *const argv[], char *const envp[]);相同的execl list v vectorp PATH e 环境变量返回值:成功调用永远不返回-1 错误 errno被设置
代码示例
- exec.c
#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>char *const ps_argv[]={"ps","-o","pid,ppid,pgrp,comm",NULL};int main(void){ pid_t pid; //创建子进程 pid=fork(); if(pid ==-1){ perror("fork"); return 1; } if(pid==0){ //加载新映像 //execl("/bin/ps","ps","-o", "pid,ppid,pgrp,comm",NULL); //execlp("ps","ps","-o", "pid,ppid,pgrp,comm",NULL); execvp("ps",ps_argv); }else{ wait(NULL); } return 0;}
使用 system 启动新的可执行程序
#include <stdlib.h>int system(const char *command);功能:执行一个shell命令参数:command:可执行命令返回值:-1 错误返回command的退出状态码。
代码示例
- system.c
#include <stdio.h>#include <sys/types.h>#include <sys/wait.h>#include <stdlib.h>#include <unistd.h>int main(void){ pid_t pid; pid=fork(); if(pid==-1){ return 1; } if(pid==0){ execl("./myt","myt",NULL); //system("myt"); exit(0); }else{ wait(NULL); } return 0;}
另外,作者在蓝桥云课上线了《Linux 操作系统原理剖析》,以 Linux 操作系统为基础对操作系统实现原理进行深入讲解,分析操作系统中的内存管理、进程管理、文件系统管理、设备管理、网络管理等几大子模块的实现原理。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。