linuxシステムプログラミングのプロセス(四):プロセスはexitを終了し、exit区別すなわちatexit関数


作者:mickole出典:http://www.cnblogs.com/mickole/
一、プロセス終了には5つの方法があります.
正常終了:
main関数からを返す
呼び出しexit 呼び出し_exit
異常終了:
呼び出しabort 信号によって終了する二、exitと_exitの違い:
linux系统编程之进程(四):进程退出exit,_exit区别即atexit函数_第1张图片
についてexit():
       #include
       void _exit(int status);
       #include
       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 par-         ent 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().
exit()について:
#include
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  addi-         tional  function  to be executed during exit processing; the new regis-         tration 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, flush-         ing of stdio(3) streams) is abandoned.  If a function has  been  regis-         tered  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. 
exitと比較すると、exit()関数はstdlibに定義されています.h中、そして_exit()はunistdに定義する.hでは、
注:exit()は終了です.入力されたパラメータはプログラム終了時のステータスコードです.0は正常終了を表し、その他は非正常終了を表します.一般的には-1または1を使います.標準CにはEXIT_があります.SUCCESSとEXIT_FAILURE 2マクロ、exit(EXIT_SUCCESS);
_exit()関数の役割は最も簡単です.プロセスを直接停止させ、使用するメモリ領域を消去し、カーネル内の様々なデータ構造を破棄します.exit()関数は、これらに基づいていくつかのパッケージを作成し、終了を実行する前にいくつかの工程を追加します.exit()関数と_exit()関数の最大の違いは、exit()関数がexitシステム呼び出しを呼び出す前にファイルの開き具合をチェックし、ファイルバッファの内容をファイルに書き戻す「I/Oバッファのクリーンアップ」です.
exit()呼び出しプロセスを終了する前に、次の手順に従います.atexit()登録された関数(出口関数)を呼び出す.ATEXIT登録時とは逆の順序で登録するすべての関数を呼び出し、プログラム終了時に自分のクリーンアップ動作を実行するように指定することができる.例えば、プログラムの状態情報をあるファイルに保存する、共有データベースへのロックなどを解除する.
2.cleanup();開いているすべてのストリームを閉じると、バッファリングされたすべての出力が書き込まれ、TMPFILE関数で作成するすべての一時ファイルが削除されます.
3.最終呼び出し_exit()関数はプロセスを終了します.
_exitは3つのことをします(man):1,Any open file descriptors belonging to the process are closed 2,any children of the process are inherited by process 1,init 3,the process's parent is sent a SIGCHLD signal
exitクリーンアップ作業が完了したら呼び出す_exitはプロセスを終了します.
三、atexit()
atexitは終了処理プログラムを登録することができ、ANSI Cは最大32個の終了処理プログラムを登録することができることを規定している.
終了ハンドラの呼び出しは登録順序とは逆です
       #include
       int atexit(void (*function)(void));
DESCRIPTION         The atexit() function registers the given function to be called at nor-         mal process termination, either via exit(3) or via return from the pro-         gram’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-2001 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 non-zero value.
サンプル・プログラム:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void fun1()
{
    printf("fun1 is called
"); } void fun2() { printf("fun2 is called
"); } int main(void) { printf("main function
"); atexit(fun1); atexit(fun2); atexit(fun1); exit(EXIT_SUCCESS); }


実行結果:
linux系统编程之进程(四):进程退出exit,_exit区别即atexit函数_第2张图片
 
forkが呼び出されると、サブプロセスは親プロセスが登録したatexitを継承します.
サンプル・プログラム:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#define ERR_EXIT(m) \
    do\
    {\
        perror(m);\
        exit(EXIT_FAILURE);\
    }\
    while (0)\

void fun1()
{
    printf("fun1 is called
"); } void fun2() { printf("fun2 is called
"); } int main(void) { pid_t pid; pid = fork(); atexit(fun1); atexit(fun2); atexit(fun1); if(pid == -1) ERR_EXIT("fork error"); if(pid == 0){ printf("this is child process
"); } if(pid > 0){ printf("this is parent process
"); } return 0; }


実行結果:
linux系统编程之进程(四):进程退出exit,_exit区别即atexit函数_第3张图片
 
atexitに登録されている関数の1つが正常に返されていないかkillされていない場合、後続の登録関数は実行されません.
サンプル・プログラム:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

void fun1()
{
    printf("fun1 is called
"); } void fun2() { printf("fun2 is called
"); kill(getpid(),SIGINT); } int main(void) { printf("main function
"); if(signal(SIGINT,SIG_DFL) == SIG_ERR){ perror("signal error"); exit(EXIT_FAILURE); } atexit(fun1); atexit(fun2); atexit(fun1); exit(EXIT_SUCCESS); }


実行結果:
linux系统编程之进程(四):进程退出exit,_exit区别即atexit函数_第4张图片
最後のfun 1が実行されなかったことがわかります