Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法…感兴趣就关注我吧!你定不会失望。
一个进程在执行完毕时,会退出。但是执行完毕一定是按照我们预想的方式执行的嘛?显然不是的
进程退出时一般会分为以下这三种情况:
我们将围绕这三个方面来谈论进程退出这一概念.我们如何分辨一个进程退出时是哪种状态呢?
我们可以通过进程退出码来判断.
例如:下面是一个我们刚学习C语言时的代码
#include
int main()
{
printf("Hello World\n");
return 0;
}
其中的return 0就是给上层函数返回值(当该进程结束时,其为进程退出码).他会存在 **$?**该环境变量中
我们可以通过echo命令来打印出上一次进程运行的退出码.
echo $?
也就是说,每一次进程的状态退出码会存入到 ** ? ∗ ∗ , 所以 ∗ ∗ ?**,所以** ?∗∗,所以∗∗?**只能存储最近一次的进程退出码
进程运行完毕可以根据结果正确与否来分为两种情况.
例如之前演示的:
#include
int main()
{
printf("Hello World\n");
return 0;
}
我们收到0之后知道这段程序按照我们预想的方式进行运行了.所以我们并不用关心他为什么会正确(现实生活中也没有人会这么问).
我们更多时候关心的是,这个进程运行完毕,但是结果错误的原因.
我们人为的规定,进程退出码为0时表示进程运行错误.那么进程退出码是其他时该如何确认是什么原因呢?
C中封装了一个strerr的函数.来解决这个问题.
传入参数为对应的错误退出码,返回值为系统中对这段退出码的描述.
我们来看看系统中的错误码描述有几种.
int main()
{
for(int i=0;i<200;i++)
printf("%d:%s\n",i,strerror(i));
return 0;
}
总共有134个(0-133).其中,0号退出码表示进程正确执行完毕.
当一个进程结果错误的时候.进程往往会保存他的错误码,在errorno中.这是一个全局变量,同样也仅能存储最近一次错误是什么原因.
例如:
int main()
{
char *p=(char*) malloc(10000000000*1000*1000*1000*4);
if(p==NULL)
{
printf("errno:%d,because : %s",errno,strerror(errno));
return errno;
}
else
{
return 0;
}
}
我们用malloc向内存申请一个空间.若p==NULL则说明申请失败了.我们就可以通过errno配合strerror读出其的错误信息.
进程异常的本质是进程收到了对应的信号而停止了进程.
大多时候,进程异常时代码是没有运行完成的.所以我们并不需要去关注他的退出码是什么.而是关注他的退出信号.
我们写一个一眼错的程序看看什么叫进程异常.
int main()
{
int a=10;
a/=0;
int *p=NULL;
*p=10;
return 0;
}
第一个是/0错误,第二个是段错误(访问了不属于自己的内存). 运行看看结果
我们打开之前的kill信号表
kill -l
这两个错误对应的信号是8号与11号.我们来看看是不是
先运行一个简单的监控程序
int main()
{
while(1)
{
printf("ing\n");
sleep(1);
}
return 0;
}
和我们的预期是一样的
我们先来看看return与exit的关系
return 为退出当前的函数.
exit 为退出当前的进程.
也就是说如果在main函数中使用,这二者差别不大. 也就是return 0 与 exit(0)等价
如果在其他函数中使用,return 会返回到上一层函数中去,而exit会直接退出这个进程.
那么exit()与_exit()呢?
exit为C封装的库函数,而_exit为系统调用
我们观察一下这个程序
int main()
{
printf("hello");
exit(0);
}
会发生什么呢?
那么,换成系统调用会发生什么呢?
int main()
{
printf("hello");
_exit(0);
}
printf并不生效了,这是为什么呢?
因为效率原因,printf打印并不会直接输出,而是直接放入到对应的缓冲区当中
而exit会先清除缓冲区,调用析构等语言层面的事情做完.再去调用_exit完成系统内核层面的结束.
而_exit直接完成系统层面的结束了.
我们也可以得出一个结论该缓冲区肯定不在内核中.因为这样exit与_exit的差别就不大了.也就不会出现上面的情况
68)]
printf并不生效了,这是为什么呢?
因为效率原因,printf打印并不会直接输出,而是直接放入到对应的缓冲区当中
而exit会先清除缓冲区,调用析构等语言层面的事情做完.再去调用_exit完成系统内核层面的结束.
而_exit直接完成系统层面的结束了.
我们也可以得出一个结论该缓冲区肯定不在内核中.因为这样exit与_exit的差别就不大了.也就不会出现上面的情况