
点击蓝字 关注我们


void exit(int status);
- #include <stdlib.h>
- void exit(int status);
- 功能:终止进程
- 参数:
- status:退出状态码。status&0377的值给父进程。
- 返回值:
- 永远不返回。
- #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 错误
- #include <stdio.h>
- #include <stdlib.h>
- void doit(int n,void *arg){
- printf("n=%d\targ:%s\n",\
- n,(char *)arg);
- return;
- }
-
-
- int main(void){
- //向进程注册退出函数
- on_exit(doit,"beijing");
- getchar();
- exit(3);
- }
执行结果

atexit(3)
- #include <stdlib.h>
- int atexit(void (*function)(void));
- 功能:注册一个函数给进程,在进程终止的时候调用该函数
- 参数:
- function:指定了要注册的函数的名字
- 返回值:
- 0 成功
- 非0 错误
- #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 进程,这种进程被成为孤儿进程。
- #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;
- }
执行结果

- #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
- #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=%d\n",\
- getpid());
- //sleep(5);
- getchar();
- exit(-1);
- }else{
- //等待子进程的结束
- wait(&s);
- if(WIFEXITED(s)){
- //子进程正常终止
- printf("status:%d\n", WEXITSTATUS(s));
- }
- //检测子进程是否被信号终止
- if(WIFSIGNALED(s)){
- //输出终止子进程的信号编号
- printf("signum :%d\n",\
- WTERMSIG(s));
- }
- printf("parent...\n");
- }
- return 0;
- }
执行结果

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=%d\n",\
- getpid());
- //sleep(5);
- getchar();
- exit(-1);
- }else{
- //非阻塞等待子进程的结束
- waitpid(-1,&s,WNOHANG);
- if(WIFEXITED(s)){
- //子进程正常终止
- printf("status:%d\n", WEXITSTATUS(s));
- }
- //检测子进程是否被信号终止
- if(WIFSIGNALED(s)){
- //输出终止子进程的信号编号
- printf("signum :%d\n",\
- WTERMSIG(s));
- }
- printf("parent...\n");
- }
- return 0;
- }
执行结果

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[]);
- 相同的exec
- l list
- v vector
- p 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;
- }
执行结果

- #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 操作系统为基础对操作系统实现原理进行深入讲解,分析操作系统中的内存管理、进程管理、文件系统管理、设备管理、网络管理等几大子模块的实现原理。

如果想学此门课程,欢迎扫文末二维码优惠学!除此之外,大家还可选择教育优惠哦~

号外!号外!
蓝桥云课专属教育优惠重磅上线啦!

仅需完成学生认证,
即享 5 折学生优惠券!
▼扫码完成学生认证▼

▲课程优惠学▲

戳戳“阅读原文”直达课程页面!