Linux环境中程序的始终

在Linux中,程序的执行从开始到结束的过程如下图所示:




首先由内核使程序执行。内核首先创建一个启动例程,然后调用exec函数使得该启动例程执行。然后启动例程从内核中取得命令行参数和环境变量值,用来调用main函数。于是开始执行main函数。在main函数中可以调用用户函数,然后可以从用户函数中通过return语句返回其主调函数。当然,我们还可以随时使得程序终止,即通过调用exit()或_exit()和_Exit()函数,这几个函数是程序进程自愿主动终止的方法,它是系统级别的,是通过直接调用exit系统调用完成。这里有两点需要强调:exit()系列函数和return的区别;几种exit函数的区别;


1、exit()系列函数和return的区别

<1>exit()函数是用来随时终止程序进程的,它是系统级别的,将直接返回到操作系统中。

<2>return语句是语言级的,它的作用是终止当前函数的运行,并将操作权返回给调用者。是在调用堆栈中返回。如果是在main函数中运行return语句,main函数的调用者是启动例程,然后启动例程通过调用exit函数来结束进程,这就是所谓的在main执行到最后一条语句的时候会隐式返回。

<3>exit()函数的参数是用来将应用程序的状态返回给操作系统,一般0状态为正常退出,非0状态为非正常退出。main函数可能有一个整型返回值,这个返回值返回给启动例程,然后启动例程将这个返回值作为exit函数的参数同样返回给操作系统。


2、exit()与_exit()和_Exit()函数的区别

主要如下图所示:



最后都是将调用exit系统调用来终止进程,但是在调用exit系统调用之前,exit()多做了两件事情:它将调用终止处理程序,并且将关闭所有打开的流。首先,进程在处理终止处理程序时,具体是调用哪些程序呢?终止处理程序主要是用来对进程终止需要进行的资源释放等操作的一些函数,是通过int atexit(void (*func) (void))函数来注册的。注意到参数是一个返回类型和参数类型均为空的函数指针,即exit()在调用终止处理程序的时候不需要对其传递参数,并且也不指望终止处理程序能够返回任何值。另外,exit()函数调用终止处理程序的顺序与atexit()函数注册这些终止处理程序的顺序是相反的。同一个终止处理函数可以被注册多次,这意味这在终止进程时,这个终止处理程序也会被执行多次。ISO C规定的一个进程可以登记多至32个函数。

我们通过一个小程序来证明一下atexit函数和exit的关系:

#include <apue.h>
#include <error.c>

static void my_exit1(void);
static void my_exit2(void);

int main()
{
        if(atexit(my_exit2) != 0)
                err_sys("can't register my_exit2");
        if(atexit(my_exit1) != 0)
                err_sys("can't register my_exit1");
        if(atexit(my_exit1) != 0)
                err_sys("can't register my_exit1");
        printf("main in done\n"); 
        return(0);
}
static void my_exit1(void)
{   
        printf("first exit handler\n"); 
}   
static void my_exit2(void)
{
        printf("second exit handler\n");
}
    
由上面的代码可以看出,函数的注册顺序是:my_exit2my_exit1 my_exit1,其中my_exit1还被注册了两次,所以在从main函数中return后将隐式调用exit()函数,将以与atexit函数注册的相反顺序调用这些被注册的终止处理程序,并且重复多次注册的函数也将被重复多次执行。结果如下:



从运行结果可以看出,my_exit1函数被执行两次,并且是逆序执行的。

发布了68 篇原创文章 · 获赞 42 · 访问量 22万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章