【Linux】进程控制-进程终止
目录
一、进程终止,OS做了什么?
二、进程终止的常见方式
1、代码跑完,结果正确
2、代码跑完,结果不正确
补充
(1)、main函数的返回值的意义是什么?
(2)、return 0的含义是什么?
(3)、退出码是什么和sterror认识
(4)、如何获取退出码
3、代码没有跑完,程序崩溃
三、如何用代码终止一个进程
1、return语句
2、exit()函数
四、知识补充
1、return和exit()区别
2、exit()和_exit()区别
3、区别示意图
五、缓冲区相关知识
1、库函数和系统调用接口
一、进程终止,OS做了什么?
创建进程,不管是fork,命令行./或者双击都会变成进程,OS要管理这些进程要创建进程对应的内核数据结构task_struct,还要为该进程创建对应的地址空间mm_struct,还要为该进程创建页表,构建映射关系,并且还要将该进程对应的代码和数据加载到内存。
因此进程终止时,OS需要释放进程申请的相关内核数据结构和对应的数据和代码,本质就是释放系统资源。
二、进程终止的常见方式
1、代码跑完,结果正确
#include<stdio.h>
#include<unistd.h>
26 int main()
27 {
28 printf("pid: %d,ppid: %d\n",getpid(),getppid());
29 return 0;
30 }
2、代码跑完,结果不正确
1 #include<stdio.h>
2 #include<unistd.h>
3
4
5
6 int sum(int top)
7 {
8 int s=0;
9 for (int i=0;i<top;i++)
10 {
11 s+=i;
12 }
13 return s;
14 }
15 int main()
16 {
17 int ret=0;
18 int res=sum(100);
19 if(res!=5050)
20 {
21 //如果运行的代码不正确 return 1
22 ret=1;
23 }
24 return ret;
25 }
[hx@VM-24-7-centos 20231203-进程终止]$ make
gcc -std=c99 -o myproc myproc.c
[hx@VM-24-7-centos 20231203-进程终止]$ ./myproc
[hx@VM-24-7-centos 20231203-进程终止]$ echo $?
1
补充
(1)、main函数的返回值的意义是什么?
返回给上一级进程,父进程或者bash,用来评判该进程执行结果用的
(2)、return 0的含义是什么?
0是退出码的一种,代表运行成功,代码对或不对用退出码判定。
非0标识的是运行结果不正确,非0值有无数个,不同的非0值可以标识不同的错误原因,方便在进程运行结束后,结果不正确时,方便定位错误的原因。
(3)、退出码是什么和sterror认识
退出码是计算机为了方便返回结果设定的,我们并不清楚返回的1、2、3、4是什么意思,所以需要做一个将对应错误码或退出码转化为字符串描述的方案 .
strerror(number)将状态码或退出码转换成字符串描述。
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 //strerror(number)将状态码或退出码转换成字符串描述。
5 int main()
6 {
7 for(int number=0;number<150;number++)
8 {
9 //查看number对应的错误原因
10 printf("%d: %s\n",number,strerror(number));
11 }
12 return 0;
13 }
14
[hx@VM-24-7-centos 20231203-进程终止]$ ls abcdef
ls: cannot access abcdef: No such file or directory
[hx@VM-24-7-centos 20231203-进程终止]$ echo $?
2
[hx@VM-24-7-centos 20231203-进程终止]$ kill -9 11111
-bash: kill: (11111) - Operation not permitted
[hx@VM-24-7-centos 20231203-进程终止]$ echo $?
1
[hx@VM-24-7-centos 20231203-进程终止]$ ./myproc
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
.................................
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
.....................
146: Unknown error 146
147: Unknown error 147
148: Unknown error 148
149: Unknown error 149
(4)、如何获取退出码
如果想在命令行中获取最近一次进程退出的退出码 通过
[hx@VM-24-7-centos 20231203-进程终止]$ echo $?
0
[hx@VM-24-7-centos 20231203-进程终止]$
3、代码没有跑完,程序崩溃
当遇到程序崩溃的时候,例如遇到野指针,除0操作,退出码无意义。一般而言,退出码对应的return语句没有被执行。
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4
5 //程序崩溃
6 int main()
7 {
8 int *p=NULL;
9 *p=1234;//野指针
10 return 0;
11 }
[hx@VM-24-7-centos 20231203-进程终止]$ ./myproc
Segmentation fault
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4
5 //程序崩溃
6 int main()
7 {
8 //int *p=NULL;
9 //*p=1234;//野指针
10
11
12 int a=10;
W> 13 a/=0;//除0操作
14 return 0;
15 }
[hx@VM-24-7-centos 20231203-进程终止]$ make
gcc -std=c99 -o myproc myproc.c
myproc.c: In function ‘main’:
myproc.c:13:6: warning: division by zero [-Wdiv-by-zero]
a/=0;//除0操作
^
[hx@VM-24-7-centos 20231203-进程终止]$ ./myproc
Floating point exception
三、如何用代码终止一个进程
1、return语句
return语句就是用来终止进程的
main函数里执行 return语句是用来终止进程
其它函数内部执行return 语句代表函数返回。
2、exit()函数
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 #include<stdlib.h>
5
6 //exit()
7 int main()
8 {
9 printf("hello world\n");
10 printf("hello world\n");
11 printf("hello world\n");
12 exit(11);
13 printf("hello world\n");
14 printf("hello world\n");
15 printf("hello world\n");
16 return 0;
17 }
[hx@VM-24-7-centos 20231203-进程终止]$ ./myproc
hello world
hello world
hello world
[hx@VM-24-7-centos 20231203-进程终止]$ echo $?
11
[hx@VM-24-7-centos 20231203-进程终止]$
四、知识补充
1、return和exit()区别
return是一个语句:return在普通函数里通常代表函数调用结束,在main函数里代表进程退出
exit是一个函数:代表在任何地点终止进程
2、exit()和_exit()区别
1、exit是C语言提供的进程终止方案,进程终止时,会把缓冲区中的内容刷新到显示屏,然后再进行进程退出
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 #include<stdlib.h>
5
6
7
8 int main()
9 {
10 printf("you can see me?\n");
11 sleep(3);
12 exit(11);
13 }
//先打印结果 再sleep三秒
[hx@VM-24-7-centos 20231203-进程终止]$ ./myproc
you can see me?
[hx@VM-24-7-centos 20231203-进程终止]$
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 #include<stdlib.h>
5
6
7 //exit()和_exit()对比
8 int main()
9 {
10 printf("you can see me?");
11 sleep(3);
12 exit(11);
13 }
//先sleep三秒 再打印结果
//去掉\n 因为数据没有\n所以数据没有立即刷新,说明这个数据当前一定在缓冲区里,最终程序退出时会刷新
//最终看到结果
[hx@VM-24-7-centos 20231203-进程终止]$ ./myproc
you can see me?[hx@VM-24-7-centos 20231203-进程终止]$ echo $?
11
2、_exit()是系统调用接口(系统层面上想终止进程,用的是_exit接口),直接终止进程,进程退出不会刷新缓冲区内的内容
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 #include<stdlib.h>
5
6 //exit()和_exit()对比
7 int main()
8 {
9 printf("you can see me?");
10 sleep(3);
11 _exit(11);
12 }
//缓冲区里的内容并没有被刷新出来
//先sleep3秒,再进程退出
[hx@VM-24-7-centos 20231203-进程终止]$ ./myproc
[hx@VM-24-7-centos 20231203-进程终止]$ echo $?
11
3、区别示意图
exit()函数最后也会调用_exit()函数,但是再调用之前还做了其它工作:
1、执行用户定义的清理函数
2、关闭所有打开的流,所有的缓存数据均被写入
3、调用_exit()函数
五、缓冲区相关知识
1、库函数和系统调用接口
os给我们提供接口是因为OS本身不相信我们,只是提供接口的方式交互,而我们对系统接口并不了解,就有人把系统接口做了封装,因此语言也就有了自己的库。
exit()底层调用的是_exit(),只不过直接调用_exit()数据没有立即刷新出来,而调用exit数据刷新出来了,那么缓冲区是谁在维护,在那一层维护呢?
这个缓冲区一定不在操作系统内部,如果是OS维护䣌,缓冲区的内容_exit()也能刷新出来,但是_exit()不能刷新缓冲区数据,而exit()可以,又因为exit()是C语言提供的函数,因此缓冲区应该由C语言提供的C标准库给我们维护的。