程序的启动与进程的终止

    C 程序总是从 main 函数开始执行,main 函数可接收命令行参数。当内核执行 C 程序时(使用一个 exec 函数),在调用 main 前会先调用一个特殊的启动例程,可执行程序文件将其指定为程序的起始地址,这是由连接编辑器设置的,而连接编辑器则由 C 编译器调用。启动例程从内核取得命令行参数和环境变量值,然后为调用 main 函数做好安排。
    让进程终止有 8 种方式,其中 5 种为正常终止,分别为:
    (1)从 main 返回;
    (2)调用 exit;
    (3)调用 _exit 或 _Exit;
    (4)最后一个线程从其启动例程返回;
    (5)从最后一个线程调用 pthread_exit。
    异常终止有 3 种方式,分别是:
    (1)调用 abort;
    (2)接到一个信号;
    (3)最后一个线程对取消请求做出响应。
    启动例程就是这样编写的:从 main 返回后立即调用 exit 函数。如果将其以 C 代码形式表示(实际上常常用汇编语言编写),则它调用 main 函数的形式可能是:
        exit(main(argc, argv));
    下面 3 个函数用于正常终止一个程序。
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);

    其中 _exit 和 _Exit 会立即进入内核,exit 则总是执行一个标准 I/O 库的清理关闭操作后才返回内核。这三个函数所带的整型参数常被称为终止状态。大多数 UNIX 系统 shell 都提供检查进程终止状态的方法。如果(a)调用这些函数时不带终止状态,或(b)main 执行了一个无返回值的 return 语句,或(c)main 没有声明返回类型为整型,则该进程的中指状态就是未定义的。而若 main 的返回类型是整型,并且 main 最后返回(隐式返回),那么该进程的终止状态就是 0。
    按照 ISO C 的规定,一个进程可调用 atexit 函数登记多个终止处理程序函数(可以使用 sysconf 函数来确定),这些函数将由 exit 以与登记时相反的顺序自动调用。同一函数如若登记多次,也会被调用多次。
#include <stdlib.h>
int atexit(void (*func)(void));   /* 返回值:若成功,返回 0;否则,返回非 0 */

    exit 首先调用各终止处理程序,然后使用 fclose 关闭所有打开流。如若程序调用 exec 函数族中的任一函数,则将清除所有已安装的终止程序。
    下图显示了一个 C 程序是如何启动的,以及它终止的各种方式。

    注意,内核使程序执行的唯一方法是调用一个 exec 函数,自愿终止的唯一方法是显示或使用 exit 隐式地调用 _exit 或 _Exit。进程也可非自愿地由一个信号来终止(图中未显示)。
    下面是一个 atexit 函数使用的示例。
#include <stdio.h>
#include <stdlib.h>

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

int main(void){
	if(atexit(my_exit2) != 0)
		printf("can't register my_exit2\n");
	if(atexit(my_exit1) != 0)
		printf("can't register my_exit1\n");
	if(atexit(my_exit1) != 0)
		printf("can't register my_exit1\n");
	printf("main is done\n");
	return 0;
}

static void my_exit1(void){
	printf("first exit handler\n");
}

static void my_exit2(void){
	printf("second exit handler\n");
}

    编译后的运行结果:
$ ./atexitDemo.out
main is done
first exit handler
first exit handler
second exit handler

猜你喜欢

转载自aisxyz.iteye.com/blog/2390393
今日推荐