结束进程

首先,我们回顾一下 C 语言中 continue, break, return 的作用:

continue: 结束本次循环

break: 跳出整个循环,或跳出 switch() 语句

return: 结束当前函数

而我们可以通过 exit() 或 _exit() 来结束当前进程。

所需头文件:

#include <stdlib.h>

void exit(int value);

功能:

结束调用此函数的进程。

参数:

status:返回给父进程的参数(低 8 位有效),至于这个参数是多少根据需要来填写。

返回值:

所需头文件:

#include <unistd.h>

void _exit(int value);

功能:

结束调用此函数的进程。

参数:

status:返回给父进程的参数(低 8 位有效),至于这个参数是多少根据需要来填写。

返回值:

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

下面的例子验证调用 exit() 函数,会刷新 I/O 缓冲区(关于缓冲区的更多详情,请看《浅谈标准I/O缓冲区》):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main(int argc, char *argv[])
{printf("hi, mike, you are so good"); // 打印,没有换行符"\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("hi, mike, you are so good"); // 打印,没有换行符"\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;
}

exit() 是可以结束 fun() 所在的进程,即可让程序结束运行,结果图如下:

等待进程结束

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

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

所需头文件:

#include <sys/types.h>

#include <sys/wait.h>

pid_t wait(int *status);

功能:

等待任意一个子进程结束,如果任意一个子进程结束了,此函数会回收该子进程的资源。

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

调用 wait() 函数的进程会挂起(阻塞),直到它的一个子进程退出或收到一个不能被忽视的信号时才被唤醒(相当于继续往下执行)。

若调用进程没有子进程,该函数立即返回;若它的子进程已经结束,该函数同样会立即返回,并且会回收那个早已结束进程的资源。

所以,wait()函数的主要功能为回收已经结束子进程的资源。


参数:

status: 进程退出时的状态信息。

如果参数 status 的值不是 NULL,wait() 就会把子进程退出时的状态取出并存入其中,这是一个整数值(int),指出了子进程是正常退出还是被非正常结束的。

这个退出信息在一个 int 中包含了多个字段,直接使用这个值是没有意义的,我们需要用宏定义取出其中的每个字段

下面我们来学习一下其中最常用的两个宏定义,取出子进程的退出信息:

WIFEXITED(status)

如果子进程是正常终止的,取出的字段值非零。

WEXITSTATUS(status)

返回子进程的退出状态,退出状态保存在 status 变量的 8~16 位。在用此宏前应先用宏 WIFEXITED 判断子进程是否正常退出,正常退出才可以使用此宏。

返回值:

成功:已经结束子进程的进程号

失败:-1

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

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 种情况:

当正常返回的时候,waitpid() 返回收集到的已经子进程的进程号;

如果设置了选项 WNOHANG,而调用中 waitpid() 发现没有已退出的子进程可等待,则返回 0;

如果调用中出错,则返回 -1,这时 errno 会被设置成相应的值以指示错误所在,如:当 pid 所对应的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid() 就会出错返回,这时 errno 被设置为 ECHILD;

测试例子:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main(int argc, char *argv[])
{pid_t pid;pid = fork(); // 创建进程if( pid < 0 ){ // 出错perror("fork");exit(0);}if( pid == 0 ){// 子进程int i = 0;for(i=0;i<5;i++){printf("this is son process\n");sleep(1);}_exit(2); // 子进程退出,数字 2 为子进程退出的状态}else if( pid > 0){ // 父进程int status = 0;// 等待子进程结束,回收子进程的资源// 此函数会阻塞// status 某个字段保存子进程调用 _exit(2) 的 2,需要用宏定义取出wait(&status); // waitpid(-1, &status, 0); // 和 wait() 没区别,0:阻塞// waitpid(pid, &status, 0); // 指定等待进程号为 pid 的子进程, 0 阻塞// waitpid(pid, &status, WNOHANG); // WNOHANG:不阻塞if(WIFEXITED(status) != 0){ // 子进程是否正常终止printf("son process return %d\n", WEXITSTATUS(status));}printf("this is father process\n");    }return 0;
}

运行结果如下:

【Linux系统编程】进程的控制:结束进程、等待进程结束相关推荐

  1. Linux系统编程--3(exec 函数族,僵尸进程和孤儿进程,wait和wait_pid回收子进程)

    exec 函数族 fork 创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支) ,子进程往往要调用一种 exec 函数以执行另一个程序.当进程调用一种 exec 函数时,该进程的用户 ...

  2. Linux系统编程总结

    day2 vim的三种工作模式 命令模式 vi hello.c zz 保存退出 2.编辑模式 i a o s (有大写)可以写东西 3.末行模式: 文本和末行模式不能直接切换 要切换回命令模式 再到末 ...

  3. 攻克 Linux 系统编程

    课程亮点 完整学习路线图,系统掌握核心知识点 内核源码深入分析,知其然更知所以然 高频问题全面汇总,精准定位症结所在 八大主题商业案例,实操中获得拔高提升 专家推荐 曾与宇文拓共事五年,他对技术的钻研 ...

  4. vbs结束进程代码_物联网学习教程—Linux系统编程之进程控制

    Linux系统编程之进程控制 一.结束进程 首先,我们回顾一下 C 语言中 continue, break, return 的作用: continue: 结束本次循环 break: 跳出整个循环,或跳 ...

  5. linux系统编程学习_(2)进程控制-- fork函数、exec函数族、回收子进程--孤儿进程僵尸进程、wait函数

    linux系统编程学习_(2)进程控制-- fork函数.exec函数族.回收子进程–孤儿进程僵尸进程.wait函数 进程控制 fork()函数 创建一个子进程. pid_t fork(void); ...

  6. Linux系统编程之进程与线程控制原语对比

    Linux系统编程之进程与线程控制原语对比 进程 线程 fork pthread_create exit pthread_exit wait pthread_join kill pthread_can ...

  7. 【Linux系统编程学习】Linux进程控制原语(fork、exec函数族、wait)

    此为牛客Linux C++和黑马Linux系统编程课程笔记. 1. fork函数 1.1 fork创建单个子进程 #include<unistd.h> pid_t fork(void); ...

  8. Linux系统编程——进程基础知识

    Linux系统编程--进程基础知识 1.程序和进程 程序,是指编译好的二进制文件,在磁盘上,不占用系统资源(cpu.内存.打开的文件.设备.锁-) 进程,是一个抽象的概念,与操作系统原理联系紧密.进程 ...

  9. 【Linux系统编程】特殊进程之守护进程

    00. 目录 文章目录 00. 目录 01. 守护进程概述 02. 守护进程查看方法 03. 编写守护进程的步骤 04. 守护进程代码 05. 附录 01. 守护进程概述 守护进程(Daemon Pr ...

  10. 【Linux系统编程】进程概述和进程号

    00. 目录 文章目录 00. 目录 01. 进程概述 02. 进程状态 03. 进程控制块 04. 进程号 05. 进程号相关函数 06. 案例实战 07. 附录 01. 进程概述 我们平时写的 C ...

最新文章

  1. 自己不清醒,却要拉更多人陪葬的人!
  2. 最牛X的GCC 内联汇编
  3. 在SQL Server 2005 Express 中添加报表服务后 (Business Intelligence Development Studio) vs2005 加载程序集问题解决办法...
  4. Tensorflow学习-工具相关
  5. C语言Huffman Encode霍夫曼编码的算法(附完整源码)
  6. 《统计学》学习笔记之时间序列分析和预测
  7. 計算機二級-java06
  8. Android时代的赢创之路
  9. Guitar Pro如何更改五线谱的符杆方向
  10. 辗转相减法的发展应用-最大比例
  11. word 生成pdf_为什么Microsoft Word生成的PDF文件这么大?
  12. 【五线谱】调号 ( 调号标识位置 | 调号标记列表 | A 大调标识原理 | F、C、G 位置标记升号 # | F 大调标识原理 | B 位置标记降号 b )
  13. 贝壳找房2018算法笔试
  14. 学习笔记DL003:神经网络第二、三次浪潮,数据量、模型规模,精度、复杂度,对现实世界冲击
  15. 学习Java真的可以改变你的人生?
  16. 2.89亿元寻求股权转让“接盘侠”!紫光存储风波未平,紫光德瑞风云再起
  17. 机房动环监控系统3大价值,第一个太惊艳了
  18. 你知道抖音的洗脑,却不知道他的产品设计有多牛
  19. 新农慕课python答案第零周答案_智慧树慕课答案农产品加工工艺学参考答案公众号...
  20. 【web程序开发】前端标签介绍

热门文章

  1. 原生android 权限管理,Android 权限管理(原生、EasyPermissions、RxPermissions)
  2. python的jsonpath_python 提取json数据的jsonPath介绍及简单使用
  3. 中考计算机考试作文,中考理化实验计算机考试作文
  4. pip安装了 但是python找不到_python安装完毕后,用pip安装提示找不到ssl模块怎么解决?...
  5. spring boot apollo demo
  6. Nuget 多平台多目标快速自动打包
  7. ssh服务、密钥登陆配置
  8. saltstack批量加用户脚本
  9. HDU 1814 Peaceful Commission / HIT 1917 Peaceful Commission /CJOJ 1288 和平委员会(2-sat模板题)...
  10. 运维与自动化运维发展概括