钩子函数|进程的终止方式

  1. 1. 进程的终止
    1. 1.1. 调用exit
    2. 1.2. _exit/_Exit
  2. 2. 钩子函数

​ 主要介绍(1)进程的终止方式;(2)钩子函数

注:标题中显示的函数数字表示该函数在man手册中所在章节(第2章的是系统调用函数,第3章的是标准函数)

进程的终止

​ 进程的终止方式可分为以下5种正常终止方式和3种异常终止方式:

正常终止:

​ 从main函数返回;

​ 调用exit;

​ 调用_exit或_Exit;

​ 最后一个线程从其启动例程返回;

​ 最后一个线程调用pthread_exit;

异常终止:

​ 调用abort;

​ 接到一个信号并终止;

​ 最后一个线程对其取消请求作出响应;

调用exit

EXIT(3)

NAME

exit - cause normal process termination

SYNOPSIS

#include <stdlib.h>

void exit(int status);

DESCRIPTION

The exit() function causes normal process termination and the value of status & 0377 is returned to the parent (see wait(2)).

All functions registered with atexit(3) and on_exit(3) are called, in the reverse order of their registration. (It is possible for one of these functions to use atexit(3) or on_exit(3) to register an additional function to be executed during exit processing; the new registration is added to the front of the list of functions that remain to be called.) If one of these functions does not return (e.g., it calls _exit(2), or kills itself with a signal), then none of the remaining functions is called, and further exit processing (in particular, flushing of stdio(3) streams) is abandoned. If a function has been registered multiple times using atexit(3) or on_exit(3), then it is called as many times as it was registered.

All open stdio(3) streams are flushed and closed. Files created by tmpfile(3) are removed.

The C standard specifies two constants, EXIT_SUCCESS and EXIT_FAILURE, that may be passed to exit() to indicate successful or unsuccessful termination, respectively.

RETURN VALUE

The exit() function does not return.

status & 0377:exit()能带回去的值就只有256种,-128~127。

_exit/_Exit

_EXIT(2)

NAME

_exit, _Exit - terminate the calling process

SYNOPSIS

#include <unistd.h>

void _exit(int status);

#include <stdlib.h>

void _Exit(int status);

DESCRIPTION

The function _exit() terminates the calling process “immediately”. Any open file descriptors belonging to the process are closed; any children of the process are inherited by process 1, init, and the process’s parent is sent a SIGCHLD signal.

The value status is returned to the parent process as the process’s exit status, and can be collected using one of the wait(2) family of calls.

The function _Exit() is equivalent to _exit().

RETURN VALUE

These functions do not return.

调用_exit/_Exit函数,不执行钩子函数,也不执行IO清理的。

什么时候用exit(),什么时候用_exit()/_Exit()?

只要出错了然后什么都不敢动了,调用_exit()/_Exit();该刷新的,正常结束的,调用exit()。

来源于《UNIX环境高级编程(第三版)》

(以下用伪码表示)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int func()
{
return 0/1/2; // 返回值有三种可能
}

int main()
{
int f;
f = func();
...???
switch(f)
{
case 0:
case 1:
case 2:
// 如果f值不是0/1/2种的任何一种
default:
exit(1);
}
}

如果f值不是0/1/2种的任何一种,有理由怀疑调用func()后,switch(f)语句前,这两个语句中间的代码出现问题,多半是写越界,把f变量的空间给覆盖写了。如果此时调用exit()函数,执行各种钩子函数,同步刷新IO等可能会扩大故障,这时候可以用_exit(),直接退出,不执行钩子函数,不刷新IO操作。当然也可以用信号,比如调用abort(),给当前进程发送signal abort信号,把自己杀死,顺便得到一个出错的现场,来分析这个现场是什么原因导致f值出现第四种情况。

钩子函数

ATEXIT(3)

NAME

atexit - register a function to be called at normal process termination

SYNOPSIS

#include <stdlib.h>

int atexit(void (*function)(void));

DESCRIPTION

The atexit() function registers the given function to be called at normal process termination, either via exit(3) or via return from the program’s main(). Functions so registered are called in the reverse order of their registration; no arguments are passed.

The same function may be registered multiple times: it is called once for each registration.

POSIX.1 requires that an implementation allow at least ATEXIT_MAX (32) such functions to be registered. The actual limit supported by an implementation can be obtained using sysconf(3).

When a child process is created via fork(2), it inherits copies of its parent’s registrations. Upon a successful call to one of the exec(3) functions, all registrations are removed.

RETURN VALUE

The atexit() function returns the value 0 if successful; otherwise it returns a nonzero value.

atexit()函数(俗称钩子函数)用于注册在程序正常退出时要执行的函数。函数原型如下:

1
2
3
#include <stdlib.h>

int atexit(void (*function)(void));

参数说明:

  • function:指向要在程序退出时执行的函数的指针。这个函数没有参数和返回值。

函数返回值:

  • 如果成功注册要执行的函数,返回值为0。
  • 如果注册失败,返回一个非零值。

注意事项:

  1. 只要是用到申请资源的内容,下面就可以挂上钩子函数,把它的逆操作挂上去。
  2. 注册的函数会以注册的顺序的逆序执行,也就是最后注册的函数会最先执行。
  3. 可以多次调用 atexit() 函数,以便在程序退出时依次执行多个函数。
  4. 如果程序因为异常或调用了 abort() 等函数导致非正常退出,那么通过 atexit() 注册的清理函数将不会被执行。

举个栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include <stdlib.h>

static void f1(void)
{
fprintf(stderr, "f1() is working.\n");
}

static void f2(void)
{
fprintf(stderr, "f2() is working.\n");
}

static void f3(void)
{
fprintf(stderr, "f3() is working.\n");
}

int main(int argc, char **argv)
{
fprintf(stderr, "Begin.\n");

atexit(f1);
atexit(f2);
atexit(f3);

fprintf(stderr, "End.\n");
exit(0);
}

编译运行结果如下:

1
2
3
4
5
6
7
8
$ make atexit
cc atexit.c -o atexit
$ ./atexit
Begin.
End.
f3() is working.
f2() is working.
f1() is working.