00. 目录

文章目录

  • 00. 目录
  • 01. 进程退出函数
  • 02. 进程退出讨论
  • 03. 回收进程资源
  • 04. 附录

01. 进程退出函数

#include <stdlib.h>void exit(int status);
功能:结束调用此函数的进程。
参数:status:返回给父进程的参数(低 8 位有效),至于这个参数是多少根据需要来填写。
返回值:无#include <unistd.h>void _exit(int status);
功能:结束调用此函数的进程。
参数:status:返回给父进程的参数(低 8 位有效),至于这个参数是多少根据需要来填写。
返回值:无#include <stdlib.h>void _Exit(int status);
功能:结束调用此函数的进程。
参数:status:返回给父进程的参数(低 8 位有效),至于这个参数是多少根据需要来填写。
返回值:无

exit() 和 _exit() 函数功能和用法是一样的,无非时所包含的头文件不一样,还有的区别就是:exit()属于标准库函数,_exit()属于系统调用函数。

02. 进程退出讨论

下面的例子验证调用 exit() 函数,会刷新 I/O 缓冲区 。

测试程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main(int argc, char *argv[])
{printf("hello world"); // 打印,没有换行符"\n"exit(0);      // 结束进程,标准库函数,刷新缓冲区,printf()的内容能打印出来// _exit(0);  // 结束进程,系统调用函数,printf()的内容不会显示到屏幕while(1); // 不让程序结束return 0;
}

测试结果如下:

上面的例子,结束进程的时候改为调用 _exit(),代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main(int argc, char *argv[])
{printf("hello world"); // 打印,没有换行符"\n"//exit(0);      // 结束进程,标准库函数,刷新缓冲区,printf()的内容能打印出来_exit(0);  // 结束进程,系统调用函数,printf()的内容不会显示到屏幕while(1);  // 不让程序结束return 0;
}

printf() 的内容是不会显示出来的,运行结果如下:

接下来,我们一起验证一下结束函数( return )和结束进程( exit() )的区别。

测试代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>void fun()
{sleep(2);return;  // 结束 fun() 函数while(1);
}int main(int argc, char *argv[])
{fun();printf("after fun\n");while(1);    // 不让程序结束return 0;
}

测试结果如下:

通过上面的运行结果得知,return 的作用只是结束调用 return 的所在函数,只要这个函数不是主函数( main() ),只要主函数没有结束,return 并不能结束进程

我们将上面例子 fun() 里的 return 改为 exit():

测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>void fun()
{sleep(2);exit(0);  // 结束当前进程while(1);
}int main(int argc, char *argv[])
{fun();printf("after fun\n");while(1);    // 不让程序结束return 0;
}

测试结果:

03. 回收进程资源

3.1 概述

在每个进程退出的时候,内核释放该进程所有的资源、包括打开的文件、占用的内存等。但是仍然为其保留一定的信息,这些信息主要主要指进程控制块PCB的信息(包括进程号、退出状态、运行时间等)。

当一个进程正常或异常终止时,内核就向其父进程发送 SIGCHLD 信号,相当于告诉父亲他哪个儿子挂了,而父进程可以通过 wait() 或 waitpid() 函数等待子进程结束,获取子进程结束时的状态,同时回收他们的资源(相当于,父亲听听死去儿子的遗言同时好好安葬它)。

父进程可以通过调用wait或waitpid得到它的退出状态同时彻底清除掉这个进程。

wait() 和 waitpid() 函数的功能一样,区别在于,wait() 函数会阻塞,waitpid() 可以设置不阻塞,waitpid() 还可以指定等待哪个子进程结束。

注意:

一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环。

3.2 wait函数

#include <sys/types.h>
#include <sys/wait.h>pid_t wait(int *status);
功能:等待任意一个子进程结束,如果任意一个子进程结束了,此函数会回收该子进程的资源。
参数:status : 进程退出时的状态信息。
返回值:成功:已经结束子进程的进程号失败: -1这个退出信息在一个 int 中包含了多个字段,直接使用这个值是没有意义的,我们需要用宏定义取出其中的每个字段。下面我们来学习一下其中最常用的两个宏定义,取出子进程的退出信息:WIFEXITED(status)如果子进程是正常终止的,取出的字段值非零。
WEXITSTATUS(status)返回子进程的退出状态,退出状态保存在 status 变量的 8~16 位。在用此宏前应先用宏 WIFEXITED 判断子进程是否正常退出,正常退出才可以使用此宏。

从本质上讲,系统调用 waitpid() 和 wait() 的作用是完全相同的,但 waitpid() 多出了两个可由用户控制的参数 pid 和 options,从而为我们编程提供了另一种更灵活的方式。

#include <sys/types.h>
#include <sys/wait.h>pid_t waitpid(pid_t pid, int *status, int options);
功能:等待子进程终止,如果子进程终止了,此函数会回收子进程的资源。参数:pid : 参数 pid 的值有以下几种类型:pid > 0  等待进程 ID 等于 pid 的子进程。pid = 0  等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid 不会等待它。pid = -1 等待任一子进程,此时 waitpid 和 wait 作用一样。pid < -1 等待指定进程组中的任何子进程,这个进程组的 ID 等于 pid 的绝对值。status : 进程退出时的状态信息。和 wait() 用法一样。options : options 提供了一些额外的选项来控制 waitpid()。0:同 wait(),阻塞父进程,等待子进程退出。WNOHANG:没有任何已经结束的子进程,则立即返回。WUNTRACED:如果子进程暂停了则此函数马上返回,并且不予以理会子进程的结束状态。(由于涉及到一些跟踪调试方面的知识,加之极少用到)返回值:waitpid() 的返回值比 wait() 稍微复杂一些,一共有 3 种情况:1) 当正常返回的时候,waitpid() 返回收集到的已经回收子进程的进程号;2) 如果设置了选项 WNOHANG,而调用中 waitpid() 发现没有已退出的子进程可等待,则返回 0;3) 如果调用中出错,则返回-1,这时 errno 会被设置成相应的值以指示错误所在,如:当 pid 所对应的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid() 就会出错返回,这时 errno 被设置为 ECHILD;

waitpid测试代码

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>int main(void)
{pid_t pid = -1;int i = 0;int status;//创建一个子进程pid = fork();if (pid < 0){perror("fork"); }//子进程if (0 == pid){for (i = 0; i < 10; i++){printf("I am child process pid: %d %d\n", getpid(), i); //usleep(500000);sleep(1);}exit(10);}//父进程//wait(&status);  //等待子进程的状态改变//WNOHANG 如果没有子进程退出 立即返回//waitpid(pid, &status, WNOHANG);waitpid(pid, &status, WUNTRACED);//如果正常退出 就返回真if (WIFEXITED(status)){printf("正常退出 %d...\n",  WEXITSTATUS(status));}else if (WIFSIGNALED(status)){printf("被信号杀死  %d..\n", WTERMSIG(status)); }else if (WIFSTOPPED(status)){printf("the child process was stopped by delivery of a signal %d\n", WSTOPSIG(status)); }else if (WIFCONTINUED(status)){printf("the child process was resumed by delivery of SIGCONT\n"); }printf("I am parent process\n"); printf("child pid: %d pid: %d ppid: %d\n", pid, getpid(), getppid());return 0;
}

执行结果:

04. 附录

4.1 参考博客:【Linux系统编程】进程的控制:结束进程、等待进程结束

【Linux系统编程】进程退出和回收进程资源相关推荐

  1. Linux系统编程(六)守护进程

    Linux系统编程(六)守护进程 一.进程组 概念 二.会话 创建会话的条件 守护进程 概念 守护进程模型 创建守护进程 一.进程组 概念 进程组,也称之为作业.代表一个或多个进程的集合.每个进程都属 ...

  2. Linux系统编程(二)孤儿进程和僵尸进程

    Linux系统编程(二) 一.exec函数族 1.exec函数 二.孤儿进程和僵尸进程 三.wait和waitpid 1.wait函数 2.waitpid函数 一.exec函数族 exec函数使用时, ...

  3. Linux系统编程【文件IO、进程、进程间通信、信号、线程、互斥】

    linux系统编程 个人通过学习,手打了一份48000字的Linux系统编程的笔记,包含了[文件IO.进程.进程间通信.信号.多线程.互斥]等知识点,并给出了大量的代码案例对每个重要的知识点进行了代码 ...

  4. 嵌入式Linux系统编程学习之十二守护进程

    文章目录 前言 一.守护进程的特性 二.daemon 进程的编程规则 1.创建子进程,父进程退出 2.在子进程中创建新会话 前言   daemon 运行在后台,也称作"后台服务进程" ...

  5. Linux系统编程----15(线程与进程函数之间的对比,线程属性及其函数,线程属性控制流程,线程使用注意事项,线程库)

    对比 进程 线程 fork pthread_create exit (10) pthread_exit (void *) wait (int *) pthread_join (,void **)阻塞 ...

  6. Linux系统编程--2(环境变量,进程控制)

    环境变量 环境变量 是指在操作系统中用来指定操作系统运行环境的一些参数 每个人用电脑的习惯不一样,比如一般把文件放到磁盘,怎么管理文件,用什么编译器,所以,环境变量就是根据每个人使用操作系统的习惯来规 ...

  7. Linux系统编程:习题,父子进程通过信号通信,实现交替数数

    Linux练习题,父子进程通过信号通信,实现交替数数. 习题思路 父子进程交替发信号进行驱动从而实现数数,值得注意的是 不管是父进程或者子进程谁先发送信号 都会面临一个问题,另外一个进程的信号捕捉函数 ...

  8. 【Linux系统编程】特殊进程之僵尸进程

    00. 目录 文章目录 00. 目录 01. 僵尸进程概述 02. 僵尸进程案例 03. 避免僵尸进程 04. 附录 01. 僵尸进程概述 进程已运行结束,但进程的占用的资源未被回收,这样的进程称为僵 ...

  9. Linux系统编程——特殊进程之僵尸进程

    僵尸进程(Zombie Process) 进程已运行结束,但进程的占用的资源未被回收,这样的进程称为僵尸进程. 在每个进程退出的时候,内核释放该进程所有的资源.包括打开的文件.占用的内存等. 但是仍然 ...

最新文章

  1. C#.NET 轻量级通用快速开发平台,DevExpress DXperience 12.2
  2. python操作系统-PYTHON-操作系统基础
  3. 我的第一个python 代码
  4. 理解复杂的C/C++声明 const, typedef , 函数指针(转贴)
  5. EM算法最完整易懂讲解
  6. HTTP报文字段说明
  7. dos命令大全 基础命令+网络的常用命令
  8. [bzoj3202][SDOI2013]项链
  9. 手机唯一标识IMEI以及与IMSI的区别
  10. 谷歌正式发布Android 12,UI更好看,应用更快,打造独属于自己的定制化属性
  11. 计算机网络期末试题及答案
  12. JavaScript--20 深入理解 Ajax
  13. 面试官:说一下你们线上JVM是如何优化的?一不小心聊了2个小时!!
  14. python情人节之玫瑰花与表白方式
  15. VUE + Element-UI 表单校验input框数据已存在
  16. java毕业设计道路桥梁工程知识文库系统Mybatis+系统+数据库+调试部署
  17. 医院云存储服务器项目背景,医疗影像云存储解决方案
  18. Linux的inode作用,Linux下inode知识
  19. 预测性维护:工业 4.0下人工智能如何改变机器设备维护方式
  20. SwiftUI——推送通知(Notifications)二三事

热门文章

  1. 西山小菜鸟之Scrapy学习笔记---爬取企查查网站公司基本信息
  2. 计算机毕业设计java+ssm妇女联合会信息网站(源码+系统+mysql数据库+Lw文档)
  3. 人工智能知识全面讲解:生成对抗网络的应用
  4. 苹果XS怎么截屏_苹果发布iOS14,有哪些值得一说的亮点
  5. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  6. ins 登录发现未知网络_如何发现未知的知识
  7. C语言图形化推箱子完整代码
  8. 什么是android应用程序未安装,应用程序未安装,教您安卓系统应用程序未安装怎么解决...
  9. 性能服务器漫画免费下拉式,奇妙漫画免费漫画
  10. Find 7 Faster Than John Von Neumann