Linux系列
文章目录
- Linux系列
- 前言
- 一、进程终止的概念
- 二、进程终止的场景
- 三、进程终止的实现
- 3.1 程序退出码
- 3.2 运行完毕结果正常
- 3.3 运行完毕结果异常
- 3.4 程序异常退出
- 总结
前言
进程终止是操作系统中,进程的一个重要阶段,他标志着进程生命周期的结束。在Linux下进程终止的方式有很多,接下来我会一一介绍。
一、进程终止的概念
进程终止是操作系统将正在运行的程序结束掉的过程。当进程终止时,操作系统会回收该进程所占用的系统资源,如内存空间、文件描述符、CPU资源等,确保系统资源高效的利用。
二、进程终止的场景
这里我们仅介绍常见的进程终止场景
场景 | 原因 |
---|---|
任务完成 | 进程顺利执行完所有预设的任务,达到结束点,自动请求操作系统终止 |
运行错误 | 进程执行过程中遇到除零错误、越界访问等 |
资源不足 | 进程向操作系统申请的内存资源无法得到满足 |
用户手动终止 | 用户通过命令行(kill命令)强制终止进程 |
总的来说会有下面三种退出场景:
1.代码运行完毕,结果正确
2.代码运行完毕,结果不正确
3.代码异常终止
三、进程终止的实现
我们结合相关代码,对上面的场景逐帧分析
3.1 程序退出码
在我们平时写的代码中,main
函数内都会有依据return 0
这表示着程序结束时返回0
(不同的退出码代表不同的涵义),这个零就是我们所写程序的退出码,但是当我们所写的程序运行出错时,它往往会给我们返回一个非零值,这时什么意思呢?首先我们要知道程序退出码是干什么的:
程序退出码是程序终止时返回给操作系统的一个整数值,用于指示程序的执行结果。它的核心是为调用者提供清晰的状态反馈,以便后续处理。
更详细的内容我会在下文穿插介绍
3.2 运行完毕结果正常
return 终止进程
这是我们接触最多的一种方式:
1 #include<stdio.h>2 int main()3 {4 printf("I am process...\n"); 5 return 0; 6 }
当我们执行这个程序后,我们只能看到程序运行的结果,程序退出码呢?其实程序退出码,返回是为了给他的父进程(这里的父进程就是bash
命令行)查看的,父进程创建出子进程来执行程序时,它需要知道子进程执行的结果(如成功、错误等)程序退出码的作用就是反馈执行状态,通常退出码为零表示成功执行,而非零值,表示不同类型的错误。我们可以通过这个命令查看程序退出码:
echo $?
$?:保存的是最近一次进程退出时的退出码
exit终止进程
想了解更多可以通过man手册查看
exit(n)
直接终止进程并返回一个指定的退出码,适用于需要立刻终止进程的场景:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<unistd.h> 4 void test() 5 { 6 printf("I am process...\n"); 7 //int *ptr=(int*)malloc(1000*1000*4); 8 exit(11);9 printf("I am process...\n"); 10 } 11 int main() 12 { 13 test(); 14 return 0; 15 }
可以看到当程序执行过,exit(11)
后程序直接退出,并返回指定退出码,不再继续向下执行。
exit
和return
的区别
在主函数中两者是等价的,但是在多层函数调用中,return
只表示当前所处函数调用完成,而exit
则会直接终止进程并返回程序退出码,当我们的程序在被调用的函数中出错时,我们就可以使用exit
直接终止程序而不是使用return
返回主函数再终止,在后面我会给出示例。
_exit终止进程
这个系统调用接口和exit
用法一样,但是不同的是:
1 #include<stdio.h>2 #include<stdlib.h>3 #include<unistd.h>4 void test()5 {6 printf("I am process..."); 7 //int *ptr=(int*)malloc(1000*1000*4);8 _exit(11);9 printf("I am process...\n");10 }11 int main()12 {13 test();14 return 0;15 }
_exit
在终止进程时,不会刷新缓冲区,而exit
会帮助进程刷新缓冲区的资源
注:在测试这一点时打印函数不可以加\n
,\n
会帮助我们刷新缓冲区资源。
3.3 运行完毕结果异常
strerror 函数
在介绍程序退出码时我们说,不同的退出码对应着不同错误信息,那么我们该如何知道退出码对应的错误信息呢?在库函数中存在strerror
函数可以帮助我们:
下面代码打印出0~5
程序退出码,所对应的信息。
1 #include<stdio.h>2 #include<stdlib.h>3 #include<unistd.h>4 #include<string.h>5 int main()6 {7 int i=0;8 for(;i<=5;i++)9 {10 printf("%d->%s\n",i,strerror(i)); 11 }12 return 0;13 }
errno 全局变量
在C/C++中给我们提供了一个全局,当程序执行错误时,系统会将变量值修改为对应的错误码,并返回(程序退出码),我们可以配合strerror
函数之间打印出对应的错误信息:
1 #include<stdio.h>2 #include<stdlib.h>3 #include<unistd.h>4 #include<string.h>5 #include<errno.h>6 int main()7 {8 int *ptr=(int*)malloc(1000*1000*1000*4);9 if(ptr==NULL)10 {11 printf("malloc error,%d->%s\n",errno,strerror(errno)); 12 }13 return 0;14 }
perror 函数
它就像一个简化版的strerror
信息,可以直接输出错误描述,格式为:
用户自定义消息:错误描述
1 #include<stdio.h>2 #include<stdlib.h>3 #include<unistd.h>4 #include<string.h>5 #include<errno.h>6 int main()7 {8 int *ptr=(int*)malloc(1000*1000*1000*4);9 if(ptr==NULL)10 {11 perror("malloc error:"); 12 } 13 return 0; 14 }
3.4 程序异常退出
这里的原因还是比较多的,今天我们先介绍kill
,我们可以使用kill
系统调用或命令强制终止进程:
kill命令
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<unistd.h> 4 #include<string.h> 5 #include<errno.h> 6 int main() 7 { 8 printf("I am prcsess......\n"); 9 sleep(100); 10 return 0; 11 }
这个好像不太好演示......
kill系统调用
第二个参数对应的信号可以通过kill -l查看
1 #include<stdio.h>2 #include<stdlib.h> 3 #include<signal.h>4 #include<unistd.h>5 int main()6 {7 pid_t id=fork();8 if(id==0)9 {10 while(1)11 {12 13 printf("I am child,pid:%d,ppid%d\n",getpid(),getppid());14 sleep(1);15 }16 }17 else if(id>0)18 {19 sleep(5);20 kill(id,SIGKILL);21 }22 else exit(1);23 return 0;24 }
总结
进程终止是我们在学习Linux系统部分比较重要的一节,本篇我们主要介绍了进程退出码的作用以及如何来获取使用它,这对我们高效的编程有很大的帮助。