Linux进程终止
文章目录
- 一、进程退出场景
- 二、进程常见退出方法
- 三、借助strerror函数查看错误原因
- 四、errno函数
- 五、进程异常终止
- 六、exit与_exit函数
- 6.1exit与return的区别
- 6.2_exit函数
- 6.3区别
- 6.4结语
一、进程退出场景
代码运行完毕,结果正确
代码运行完毕,结果不正确
代码异常终止
结果正确,我们是不关心为什么跑对的
结果不正确,我们才关心为什么不正确
二、进程常见退出方法
正常终止(可以通过echo $?查看进程退出码)
1 #include <stdio.h>2 #include <unistd.h>3 int main()4 {5 printf("hello world\n");6 return 0; 7 }
return 0这个0表示的是进程的退出码,表征进程的运行结果是否正确,0->success
[wyx@hcss-ecs-000a lesson7_cont]$ ./cont
hello world
[wyx@hcss-ecs-000a lesson7_cont]$ echo $?
0
进程中一般而言是父进程关心子进程的运行情况,更多的要关心子进程为什么不正确
所以可以用return的不同的返回值数字,表征不同的出错原因–退出码
main函数的返回值,本质表示:进程运行完成时是否是正确的结果,如果不是,可以用不同的数字,表示不同的出错原因
return 1;
[wyx@hcss-ecs-000a lesson7_cont]$ echo $?
1
[wyx@hcss-ecs-000a lesson7_cont]$ echo $?
0
[wyx@hcss-ecs-000a lesson7_cont]$ echo $?
0
$?保存的是最近一次进程退出的时候的退出码
当程序运行完毕的时候,退出码就保存在了?这个变量
第二次查看的时候查看的是第一次echo的退出码,第一次echo命令是正确
三、借助strerror函数查看错误原因
但是这种0、1、2显然不是给我们看的,是给机器看的,我们需要看的是错误原因
所以我们就需要strerror函数来查看具体的错误原因
char *strerror(int errnum);
这个函数接受一个错误编号errnum作为参数,通常是errno变量的值。它返回一个指向错误消息字符串的指针,这个字符串描述了对应的错误。
1 #include <stdio.h>2 #include <unistd.h>3 #include <string.h>4 int main()5 {6 for(int i=0;i<=200;i++)7 {8printf("strerror[%d] is %s\n",i,strerror(i)); 9 }10 return 0;11 }
通过对错误信息的打印就能让我们用户了解到具体的错误原因
strerror[0] is Success
strerror[1] is Operation not permitted
strerror[2] is No such file or directory
strerror[3] is No such process
strerror[4] is Interrupted system call
strerror[5] is Input/output error
strerror[6] is No such device or address
strerror[7] is Argument list too long
strerror[8] is Exec format error
strerror[9] is Bad file descriptor
strerror[10] is No child processes
strerror[11] is Resource temporarily unavailable
strerror[12] is Cannot allocate memory
strerror[13] is Permission denied
strerror[14] is Bad address
strerror[15] is Block device required
strerror[16] is Device or resource busy
strerror[17] is File exists
strerror[18] is Invalid cross-device link
strerror[19] is No such device
strerror[20] is Not a directory
strerror[21] is Is a directory
strerror[22] is Invalid argument
strerror[23] is Too many open files in system
strerror[24] is Too many open files
strerror[25] is Inappropriate ioctl for device
strerror[26] is Text file busy
strerror[27] is File too large
strerror[28] is No space left on device
strerror[29] is Illegal seek
strerror[30] is Read-only file system
strerror[31] is Too many links
strerror[32] is Broken pipe
strerror[33] is Numerical argument out of domain
strerror[34] is Numerical result out of range
strerror[35] is Resource deadlock avoided
strerror[36] is File name too long
strerror[37] is No locks available
strerror[38] is Function not implemented
strerror[39] is Directory not empty
strerror[40] is Too many levels of symbolic links
strerror[41] is Unknown error 41
strerror[42] is No message of desired type
strerror[43] is Identifier removed
strerror[44] is Channel number out of range
strerror[45] is Level 2 not synchronized
strerror[46] is Level 3 halted
strerror[47] is Level 3 reset
strerror[48] is Link number out of range
strerror[49] is Protocol driver not attached
strerror[50] is No CSI structure available
strerror[51] is Level 2 halted
strerror[52] is Invalid exchange
strerror[53] is Invalid request descriptor
strerror[54] is Exchange full
strerror[55] is No anode
strerror[56] is Invalid request code
strerror[57] is Invalid slot
strerror[58] is Unknown error 58
strerror[59] is Bad font file format
strerror[60] is Device not a stream
strerror[61] is No data available
strerror[62] is Timer expired
strerror[63] is Out of streams resources
strerror[64] is Machine is not on the network
strerror[65] is Package not installed
strerror[66] is Object is remote
strerror[67] is Link has been severed
strerror[68] is Advertise error
strerror[69] is Srmount error
strerror[70] is Communication error on send
strerror[71] is Protocol error
strerror[72] is Multihop attempted
strerror[73] is RFS specific error
strerror[74] is Bad message
strerror[75] is Value too large for defined data type
strerror[76] is Name not unique on network
strerror[77] is File descriptor in bad state
strerror[78] is Remote address changed
strerror[79] is Can not access a needed shared library
strerror[80] is Accessing a corrupted shared library
strerror[81] is .lib section in a.out corrupted
strerror[82] is Attempting to link in too many shared libraries
strerror[83] is Cannot exec a shared library directly
strerror[84] is Invalid or incomplete multibyte or wide character
strerror[85] is Interrupted system call should be restarted
strerror[86] is Streams pipe error
strerror[87] is Too many users
strerror[88] is Socket operation on non-socket
strerror[89] is Destination address required
strerror[90] is Message too long
strerror[91] is Protocol wrong type for socket
strerror[92] is Protocol not available
strerror[93] is Protocol not supported
strerror[94] is Socket type not supported
strerror[95] is Operation not supported
strerror[96] is Protocol family not supported
strerror[97] is Address family not supported by protocol
strerror[98] is Address already in use
strerror[99] is Cannot assign requested address
strerror[100] is Network is down
strerror[101] is Network is unreachable
strerror[102] is Network dropped connection on reset
strerror[103] is Software caused connection abort
strerror[104] is Connection reset by peer
strerror[105] is No buffer space available
strerror[106] is Transport endpoint is already connected
strerror[107] is Transport endpoint is not connected
strerror[108] is Cannot send after transport endpoint shutdown
strerror[109] is Too many references: cannot splice
strerror[110] is Connection timed out
strerror[111] is Connection refused
strerror[112] is Host is down
strerror[113] is No route to host
strerror[114] is Operation already in progress
strerror[115] is Operation now in progress
strerror[116] is Stale file handle
strerror[117] is Structure needs cleaning
strerror[118] is Not a XENIX named type file
strerror[119] is No XENIX semaphores available
strerror[120] is Is a named type file
strerror[121] is Remote I/O error
strerror[122] is Disk quota exceeded
strerror[123] is No medium found
strerror[124] is Wrong medium type
strerror[125] is Operation canceled
strerror[126] is Required key not available
strerror[127] is Key has expired
strerror[128] is Key has been revoked
strerror[129] is Key was rejected by service
strerror[130] is Owner died
strerror[131] is State not recoverable
strerror[132] is Operation not possible due to RF-kill
strerror[133] is Memory page has hardware error
当我们查看一条不存在的文件的时候
[wyx@hcss-ecs-000a lesson7_cont]$ ll
total 20
-rwxrwxr-x 1 wyx wyx 8416 Sep 18 19:13 cont
-rw-rw-r-- 1 wyx wyx 166 Sep 18 19:16 cont.c
-rw-rw-r-- 1 wyx wyx 60 Sep 18 18:40 makefile
[wyx@hcss-ecs-000a lesson7_cont]$ ls hello.txt
ls: cannot access hello.txt: No such file or directory
[wyx@hcss-ecs-000a lesson7_cont]$ echo $?
2
这和2号退出码就对上了
我们把ls看作一个正在运行的进程,ls检测到这个文件不存在,并且把2转化为错误描述给我们打出来了
系统提供的错误码和错误码描述是有对应关系的
父进程关心子进程的退出码本质还是用户关心
四、errno函数
errno 是一个整数类型的变量,当库函数遇到错误时,会将相应的错误代码赋值给 errno,以便程序可以根据这些错误代码来执行相应的错误处理。
他会将最近一次失败的原因告诉你,可能你代码里面有四五个错误,但是他只会报最后一个错误
errno捕获的是库函数出错,你除0错误这种运行错误是不归errno管的
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <errno.h>
6 int main()
7 {
8 int ret=0;9 char* str=(char*)malloc(1000*1000*1000*4); 10 if(str==NULL)11 {12 printf("malloc error,%d :%s\n",errno,strerror(errno));13 ret=errno;14 }15 return ret;16 }
[wyx@hcss-ecs-000a lesson7_cont]$ ./cont
malloc error,12 :Cannot allocate memory
五、进程异常终止
进程异常终止我们是不需要关心进程的退出码的,就像你考试作弊被抓你考满分和考0分是没有区别的,都没有意义批改
6 int main()7 {8 char *p=NULL;9 *p=100; 10 return 0;11 }
[wyx@hcss-ecs-000a lesson7_cont]$ ./cont
Segmentation fault
这个是野指针错误
进程退出异常,本质是我们的进程收到了对应的信号
[wyx@hcss-ecs-000a lesson7_cont]$ kill -l1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
信号我们在后续的学习中会了解到,这里我们浅浅的用一下,野指针错误本质是进程收到了11号信号
6 int main()7 {8 while(1)9 {10 printf("my pid is %d\n",getpid());11 sleep(1); 12 }13 return 0;14 }
[wyx@hcss-ecs-000a lesson7_cont]$ kill -11 28803
当我们在这个进程中向他发送了11号信号,不管这个进程并没有出现野指针错误,进程还是会终止并向我们报出野指针错误的原因
六、exit与_exit函数
在main函数或者在程序当中调用exit,exit里面的数字就是当前进程对应的退出码
6.1exit与return的区别
exit和return在main函数里面的功能都是一样的
6 void show()7 {8 printf("begin\n");9 printf("begin\n");10 printf("begin\n");11 printf("begin\n");12 exit(13);13 printf("end\n"); 14 printf("end\n");15 printf("end\n");16 printf("end\n");17 }18 int main()19 {20 show();21 printf("hello world\n");22 return 12;23 }[wyx@hcss-ecs-000a lesson7_cont]$ ./cont
begin
begin
begin
begin
[wyx@hcss-ecs-000a lesson7_cont]$ echo $?
13
在任意地方调用exit,都表示进程直接退出,在函数内return只表示当前函数返回
exit和return在main函数都表示进程退出
6.2_exit函数
void show()7 {8 printf("begin\n");9 printf("begin\n");10 printf("begin\n");11 printf("begin\n");12 // exit(13);13 _exit(3); 14 printf("end\n");15 printf("end\n");16 printf("end\n");17 printf("end\n");18 }
[wyx@hcss-ecs-000a lesson7_cont]$ ./cont
begin
begin
begin
begin
[wyx@hcss-ecs-000a lesson7_cont]$ echo $?
3
由此可见_exit和exit一样都表示进程退出
6.3区别
6 int main()7 {8 printf("hello\n");9 _exit(0); 10 }
[wyx@hcss-ecs-000a lesson7_cont]$ ./cont
这是_exit的
6 int main()7 {8 printf("hello\n");9 exit(0); 10 }
[wyx@hcss-ecs-000a lesson7_cont]$ ./cont
hello
这是exit的
通过运行结果我们可以发现exit会帮忙刷新缓冲区,而_exit不会刷新缓冲区
exit是库函数,它会先将你的数据做刷新,然后再调用_exit
_exit是系统调用接口
在进程地址空间我们可以学习到,地址空间又被分为内存空间和用户空间,倘若缓冲区在内核的话,由于操作系统不会做浪费空间和内存的事情,那么他就必定会对在内核的缓冲区做刷新,但是没有显示结果这表明缓冲区必然在用户空间里面
6.4结语
异常终止这里只是浅谈了一下,后面还会继续学习到
进程终止本身没有什么难度,也是为进程等待做了一些铺垫