💓博主CSDN主页:杭电码农-NEO💓
⏩专栏分类:Linux从入门到精通⏪
🚚代码仓库:NEO的学习日记🚚
🌹关注我🫵带你学更多操作系统知识
🔝🔝
进程终止
- [1. 前言](#1. 前言)
- [2. 文章整体结构脉络](#2. 文章整体结构脉络)
- [3. 从main函数return进程](#3. 从main函数return进程)
- [4. 使用库函数exit终止进程](#4. 使用库函数exit终止进程)
- [5. 系统调用_exit和exit的区别](#5. 系统调用_exit和exit的区别)
- [6. 进程异常终止的场景](#6. 进程异常终止的场景)
- [7. perror函数以及变量errno](#7. perror函数以及变量errno)
- [8. 总结](#8. 总结)
1. 前言
从这篇文章开始,将学习有关进程
控制的内容,包括:进程终止,进程等待
和进程的程序替换
,内容不多,难度中等
请同学们耐心学习!
cpp
比起直接在界面输入CTRL+C
来终止一个进程外,我们更喜欢使用
一些函数接口(系统接口)来控制进程退出
一个进程的退出分为正常退出和异常退出
本章重点:
本篇文章着重讲解进程退出时
的三种场景以及常见的退出方法,
并且对比C库函数exit和系统调用
函数_exit的区别与联系.最后我们将
使用信号来模拟一些非正常退出的情况
2. 文章整体结构脉络
我们先把整篇文章的结构梳理出来
首先进程有三个退出场景:
代码执行完,结果正确
代码执行完,结果不正确
代码异常终止了
第一,二种退出场景都是
属于正常退出的范围,正常退出
又有以下常见的方法:
从main函数返回
调用exit终止进程
调用_exit终止进程
第三种退出场景是异常退出
异常退出往往是信号导致的,
我们熟悉的一个信号有:
CTRL+c,信号终止进程
全片文章将围绕以上内容做讲解!
3. 从main函数return进程
我们之前写C/C++代码时总会在写了
int main后写return 0,但是程序只能
return 0吗?答案是肯定不是!
先给出两个结论:
结论一:
-
非main函数执行到return语句时
代表此函数执行完毕! -
main函数执行到return语句时
代表此进程执行完毕!
结论二:
-
程序正常执行完毕并且结果
正确时返回0 -
程序正常执行完毕但结果不正确
时返回非0
有一个问题浮现在我们眼前,既然
结果不正确的返回值是非0,但是
非0有很多值,1,2,3,4,5等等,它们
分别有什么含义呢?不懂就去验证!
在验证前首先要明白一个函数:
它可以将错误码转换为错误字符串
cpp
int main()
{
int i=0;
for(i=0;i<200;i++)
{
printf("[%d]: %s\n",i,strerror(i));
}
return 0;
}
不出所料,0对应成功!,
并且在134号错误以后,就是 未知错误了
查看最近进程的退出码:
使用指令:
echo $?
写个代码,直接return来测试一下:
cpp
int main()
{
return 66;
}
4. 使用库函数exit终止进程
exit的参数即为错误码
,和main函数
的return值是一个意思
exit函数和return的区别:
-
return只有在main中使用时才
代表此进程退出 -
exit函数在程序任一地方使用都
可以直接退出程序,并且返回错误码
写一段代码验证一下:
cpp
void test1()
{
exit(10);
}
void test2()
{
exit(20);
}
int main()
{
test1();
exit(50);
test2();
return 0;
}
这里使用echo $?明显打印
出来的退出码是10!
5. 系统调用_exit和exit的区别
我们查看man的二号手册
可以看见_exit系统调用:
它和exit一样都是终止进程
并且_exit的参数也代表错误码
那么它们两个有什么区别呢?
我使用下面两段代码来验证:
一段用exit一段用_exit:
cpp
代码一:
printf("你可以看见我吗?");
sleep(1); //睡眠一秒
exit(10);
代码二:
printf("你可以看见我吗?");
sleep(1); //睡眠一秒
_exit(10);
下面两个图片对应运行结果:
直接看图片效果不是很好,这里建议
同学们自己去打一下这段代码
现象: 第一个打印了文字,而第二个没有打印
我们知道,printf打印的数据如果不使用
\n换行的话,数据会被存储到缓冲区里,
暂时不会打印出来,然而使用exit函数
结束进程后,缓冲区的数据被打印出来了
所以可以得出结论:exit函数会帮助我们
刷新缓冲区的数据,然而_exit函数不会
小思考:
既然exit是C语言提供的库函数
而_exit是操作系统提供的系统调用
_exit无法刷新缓冲区是不是说明缓冲区
压根就不在操作系统内?也就是说缓冲区
不由操作系统来维护,而是由C标准维护?
答案是,正确的!
6. 进程异常终止的场景
当我们在命令行输入CTRL+C传递
信号杀掉程序时,这是异常终止.
当程序中出现使用野指针或数组越界写入
时,程序会崩溃,崩溃也是进程异常结束
比如:
cpp
情况一:
int* p = NULL;
*p = 20;
情况二:
int a[10]={0};
a[11]=10;
此时运行程序后,程序会退出
这时候再去使用指令:echo $?
就没有意义了!
程序异常崩溃,退出码无意义
这是因为一般而言,退出码对应的
return语句还没执行到就已经崩溃了!
7. perror函数以及变量errno
errno是C语言中的一个全局变量
它里面存储的是最近的一个错误码
比如使用fopen函数打开文件时,
如果打开失败了,不仅仅文件指针fp
会被赋值为NULL,此时错误码errno
也会被系统自动赋值!
perror是C语言中常用的关于错误的函数
perror函数总是和errno搭配在一起
此函数会输出errno错误码对应的错误
信息,并且,perror的参数代表是哪个地方
有问题,是用户自己决定的!比如我们通常
这样来写一段代码:
cpp
FILE* fp = fopen("csdn.txt","r");
if(fp==NULL)
{
perror("fopen");
exit(1);
}
注意:打印出来的信息中,前面的fopen:
是用户输入的信息,后面的语句是errno
错误码对应的错误信息
8. 总结
进程终止话题是进程控制中最简单
的话题,学好进程终止可以提高我们
代码的可阅读性,可以把错误信息
展现的更加明了!
在本篇文章中出现的缓冲区概念只用于
区别exit和_exit的作用,更多关于缓冲区的
内容,我们将在Linux的基础IO中讲解!
🔎 下期预告:Linux进程等待 🔍