C语言详解分析进程控制中进程终止的实现

 更新时间:2022年08月29日 09:48:29   作者:小小酥诶  
当进程完成执行最后语句并且通过系统调用 exit() 请求操作系统删除自身时,进程终止。这时,进程可以返回状态值(通常为整数)到父进程(通过系统调用 wait())。所有进程资源,如物理和虚拟内存、打开文件和 I/O 缓冲区等,会由操作系统释放

进程退出的形式

进程退出的几种情况

  • 正常退出(自愿,代码运行完其结果正确)
  • 错误退出(自愿,代码运行完其结果不正确)
  • 异常退出(非自愿,代码异常直接终止)
  • 被其他进程终止(非自愿)

自愿退出会返回一个退出码,由父进程接收。

在Linux上可以使用命令echo $?显示最近一次退出的进程返回的退出码

  //现有如下代码,源文件名为mycode.c
 # include <stdio.h>
 int main(void)
 {
   printf("i am testing\n");                                                                                                                                     
   return 0;
 }

运行以上代码……

使用命令echo $?显示退出码

正常退出的退出码为0,错误退出的退出码为非0

退出码反应了进程退出的原因。所以有必要知道这些退出码究竟代表着什么。

strerror()函数的作用就是以字符的形式返回退出码。

//所在头文件
<string.h>
//函数原型
char* strerror(int errNum);
//可以使用下面代码查看退出码对应的信息
 # include <stdio.h>
 # include <string.h>
 int main(void)
 {
   for(int i = 0; i < 135; i++)                                                                                                                                  
   {
     printf("%d: %s\n", i, strerror(i));
   }
   return 0;
 }

Linux系统上一共有134个退出码,退出码“134”就已经不认识它了。

0: Success
1: Operation not permitted
2: No such file or directory
3: No such process
4: Interrupted system call
5: Input/output error
6: No such device or address
7: Argument list too long
8: Exec format error
9: Bad file descriptor
10: No child processes
11: Resource temporarily unavailable
12: Cannot allocate memory
13: Permission denied
14: Bad address
15: Block device required
16: Device or resource busy
17: File exists
18: Invalid cross-device link
19: No such device
20: Not a directory
21: Is a directory
22: Invalid argument
23: Too many open files in system
24: Too many open files
25: Inappropriate ioctl for device
26: Text file busy
27: File too large
28: No space left on device
29: Illegal seek
30: Read-only file system
31: Too many links
32: Broken pipe
33: Numerical argument out of domain
34: Numerical result out of range
35: Resource deadlock avoided
36: File name too long
37: No locks available
38: Function not implemented
39: Directory not empty
40: Too many levels of symbolic links
41: Unknown error 41
42: No message of desired type
43: Identifier removed
44: Channel number out of range
45: Level 2 not synchronized
46: Level 3 halted
47: Level 3 reset
48: Link number out of range
49: Protocol driver not attached
50: No CSI structure available
51: Level 2 halted
52: Invalid exchange
53: Invalid request descriptor
54: Exchange full
55: No anode
56: Invalid request code
57: Invalid slot
58: Unknown error 58
59: Bad font file format
60: Device not a stream
61: No data available
62: Timer expired
63: Out of streams resources
64: Machine is not on the network
65: Package not installed
66: Object is remote
67: Link has been severed
68: Advertise error
69: Srmount error
70: Communication error on send
71: Protocol error
72: Multihop attempted
73: RFS specific error
74: Bad message
75: Value too large for defined data type
76: Name not unique on network
77: File descriptor in bad state
78: Remote address changed
79: Can not access a needed shared library
80: Accessing a corrupted shared library
81: .lib section in a.out corrupted
82: Attempting to link in too many shared libraries
83: Cannot exec a shared library directly
84: Invalid or incomplete multibyte or wide character
85: Interrupted system call should be restarted
86: Streams pipe error
87: Too many users
88: Socket operation on non-socket
89: Destination address required
90: Message too long
91: Protocol wrong type for socket
92: Protocol not available
93: Protocol not supported
94: Socket type not supported
95: Operation not supported
96: Protocol family not supported
97: Address family not supported by protocol
98: Address already in use
99: Cannot assign requested address
100: Network is down
101: Network is unreachable
102: Network dropped connection on reset
103: Software caused connection abort
104: Connection reset by peer
105: No buffer space available
106: Transport endpoint is already connected
107: Transport endpoint is not connected
108: Cannot send after transport endpoint shutdown
109: Too many references: cannot splice
110: Connection timed out
111: Connection refused
112: Host is down
113: No route to host
114: Operation already in progress
115: Operation now in progress
116: Stale file handle
117: Structure needs cleaning
118: Not a XENIX named type file
119: No XENIX semaphores available
120: Is a named type file
121: Remote I/O error
122: Disk quota exceeded
123: No medium found
124: Wrong medium type
125: Operation canceled
126: Required key not available
127: Key has expired
128: Key has been revoked
129: Key was rejected by service
130: Owner died
131: State not recoverable
132: Operation not possible due to RF-kill
133: Memory page has hardware error
134: Unknown error 134

Linux上一切皆为文件,指令也是一个文件,当使用不存在的指令时,就会出现报错信息。

其退出码为2,退出码2代表的含义为: No such file or directory(没有这样的文件或目录)

进程退出的几种方法

正常终止的3种方法:

  • main函数返回
  • 调用exit
  • 调用_exit

最常见的进程终止莫过于main函数返回了!需要注意main函数中返回才是进程退出,而非main函数返回并不能正常终止进程,只是函数返回。

【调用exit】

//所在头文件
 #include <stdlib.h>
 //exit函数原型
 void exit(int status);

exit函数是语言层面的函数,是对系统调用函数_exit的封装。

它可以在main函数中调用,也可以在非main函数中调用,都可以达到终止进程的目的。

C标准还规定了两个宏EXIT_SUCCESS和EXIT_FAILURE可以作为exit的参数,用来指示这个进程是正常退出还是错误退出。

 # include <stdio.h>
 # include <string.h>
 # include <stdlib.h>
 int main(void)
 {
   printf("i am testing\n");
   exit(EXIT_SUCCESS);                                                                                                                                           
   return 0;
 }

 # include <stdio.h>
 # include <string.h>
 # include <stdlib.h>
 int main(void)
 {
   printf("i am testing\n");
   exit(EXIT_FAILURE);     //修改exit函数的参数                                                                                                                                      
   return 0;
 }

【调用_exit函数】

//所在头文件
#include <unistd.h>
//_exit函数原型
void _exit(int status);

_exit是系统调用函数。_exit函数的本质就是调用了系统调用函数_exit。

exit函数封装了系统调用_exit,exit函数还做了其他的事情。

 # include <stdio.h>
 # include <string.h>
 # include <stdlib.h>
 # include <unistd.h>
 int main(void)
 {
   printf("i am testing"); //没有“\n”
   sleep(2);
   exit(EXIT_SUCCESS);
   return 0;                                                                                                                                                     
 }

代码运行的现象:休眠2秒后,在屏幕上打印“i am testing”.

因此,可以看出,exit函数会冲刷缓冲区……

现在换做_exit函数来终止进程。

 # include <stdio.h>
 # include <string.h>
 # include <stdlib.h>
 # include <unistd.h>
 int main(void)
 {
   printf("i am testing"); //没有“\n”
   sleep(2);
   _exit(EXIT_SUCCESS);
   return 0;                                                                                                                                                     
 }

代码运行的现象:休眠两秒后,并没有在屏幕上显示预期的“i am testing”,就终止进程了。

因此可看出,_exit函数并不会冲刷缓冲区……

实际上,_exit系统调用函数只是简单地终止了进程,并不会做其他的工作。而exit函数在调用_exit函数之前还会做一些其他的工作:

  • 执行用户定义的清理函数
  • 冲刷缓冲区,关闭所有的流等。
  • 调用_exit函数

main函数返回,本质上是把返回值作为参数传给exit函数,最后还是调用exit函数。

到此这篇关于C语言详解分析进程控制中进程终止的实现的文章就介绍到这了,更多相关C语言进程终止内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • 基于OpenCv的运动物体检测算法

    基于OpenCv的运动物体检测算法

    这篇文章主要为大家详细介绍了基于OpenCv的运动物体检测算法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • C语言二分法求解方程根的两种方法

    C语言二分法求解方程根的两种方法

    这篇文章主要为大家详细介绍了C语言二分法求解方程根的两种方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-06-06
  • opencv4.5.4+VS2022开发环境搭建的实现

    opencv4.5.4+VS2022开发环境搭建的实现

    本文主要介绍了opencv4.5.4+VS2022开发环境搭建的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • C++使用ifstream读取文件内容的示例详解

    C++使用ifstream读取文件内容的示例详解

    这篇文章主要为大家详细介绍了C++如何使用ifstream读取文件内容的功能,文中的示例代码讲解详细,具有一定的参考价值,感兴趣的可以了解一下
    2023-03-03
  • C语言轮转数组的三种实现

    C语言轮转数组的三种实现

    轮转数组是一种将数组元素循环移动的处理方式,它通常用于解决一些需要对固定长度的数组进行循环滚动处理的问题,本文就介绍了C语言轮转数组的三种实现,感兴趣的可以了解一下
    2023-08-08
  • C语言中操作密码文件的一些函数总结

    C语言中操作密码文件的一些函数总结

    这篇文章主要介绍了C语言中操作密码文件的一些函数总结,包括setpwent()函数和getpwent()函数以及endpwent()函数,需要的朋友可以参考下
    2015-08-08
  • C++实现简易反弹小球游戏的示例代码

    C++实现简易反弹小球游戏的示例代码

    我们利用printf 函数实现一个在屏幕上弹跳的小球。弹跳的小球游戏比较简单、容易入门,也是反弹球消砖块、接金币、台球等很多游戏的基础,感兴趣的可以了解一下
    2022-10-10
  • C++ 实例之九宫格广度优先遍历

    C++ 实例之九宫格广度优先遍历

    这篇文章主要介绍了C++ 实例之九宫格广度优先遍历的相关资料,需要的朋友可以参考下
    2017-05-05
  • 详解C语言中fseek函数和ftell函数的使用方法

    详解C语言中fseek函数和ftell函数的使用方法

    这篇文章主要介绍了C语言中fseek函数和ftell函数的使用方法,两个函数分别用于设置和返回文件指针stream的位置,需要的朋友可以参考下
    2016-03-03
  • C++中字符串与整型及浮点型转换全攻略

    C++中字符串与整型及浮点型转换全攻略

    C++算法刷题等过程中经常会遇到字符串与数字类型的转换,在这其中虽然朴素的算法有不少,但是对于double等类型还是可以说遇到一些麻烦,所以今天就来说说使用C++标准库中的函数实现这些功能。感兴趣的小伙伴一起参与阅读吧
    2021-09-09

最新评论