atexit가 등록한 함수는main 함수 다음에 실행됩니까?

18526 단어 main
atexit 함수와 알고 지낸 지 오래되었는데, man 매뉴얼에서 atexit에 대한 설명은 다음과 같다.
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.

언뜻 보기에는 다음과 같은 인상이 형성되었다. "오,atexit 함수는 함수 A를 등록해서main 함수를 종료한 후에 함수 A를 실행해야 프로세스가 철저하게 오버된다."
작업 중에 잘못된 버그를 만났을 때 로그에서 프로세스가atexit에 등록된 함수를 실행할 때main 함수 안의 라인은 여전히 즐겁게 실행되고 있음을 발견했다. 이런 현상은 나의 이전의 인식을 전복시켜서atexit에 등록된 함수가 도대체 언제 실행되는지 다시 생각해야만 했다."main 함수 종료"란 무엇입니까?
이전 간단한 코드:
 1 #include <stdio.h>

 2 #include <stdlib.h>

 3 #include <unistd.h>

 4 #include <pthread.h>

 5 

 6 void bye(void)

 7 {

 8     printf("before bye
"); 9 sleep(10); 10 printf("after bye
"); 11 } 12 13 void *do_thread(void) 14 { 15 while(1) 16 { 17 printf("--------------I'm thread!
"); 18 sleep(1); 19 } 20 } 21 22 int main(void) 23 { 24 pthread_t pid_t; 25 26 atexit(bye); 27 pthread_create(&pid_t, NULL, (void *)do_thread, NULL); 28 29 exit(EXIT_SUCCESS); 30 }

위의 프로그램은 먼저atexit로 프로그램이 정상적으로 종료된 후의 실행 함수를 등록한 다음에 정보를 끊임없이 출력하는 데 사용할 라인을 만들고 메인 라인은 exit를 실행한다.
실행 프로그램은 무엇을 출력합니까?
내가 처음에 추측한 운행 결과는 다음과 같다.
before bye
after bye
또는:
--------------I'm thread!
before bye
after bye
내 이해에서bye()는main 함수를 종료한 후에 실행하기 때문에, 그때main 함수에 생성된 라인은 존재하지 않을 것이며, 코드는bye() 함수를 조용히 실행할 것이다.사실이 증명하듯이, 나는 너무 당연하다고 생각한다.
위의 프로그램의 실제 실행 결과는 다음과 같습니다.
 1 before bye

 2 --------------I'm thread!

 3 --------------I'm thread!

 4 --------------I'm thread!

 5 --------------I'm thread!

 6 --------------I'm thread!

 7 --------------I'm thread!

 8 --------------I'm thread!

 9 --------------I'm thread!

10 --------------I'm thread!

11 --------------I'm thread!

12 after bye

왜 bye()를 실행할 때 라인이 아직 있습니까?
exit () 함수의 원본을 보십시오.
  1 /* Copyright (C) 1991,95,96,97,99,2001,2002,2005,2009

  2    Free Software Foundation, Inc.

  3    This file is part of the GNU C Library.

  4 

  5    The GNU C Library is free software; you can redistribute it and/or

  6    modify it under the terms of the GNU Lesser General Public

  7    License as published by the Free Software Foundation; either

  8    version 2.1 of the License, or (at your option) any later version.

  9 

 10    The GNU C Library is distributed in the hope that it will be useful,

 11    but WITHOUT ANY WARRANTY; without even the implied warranty of

 12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

 13    Lesser General Public License for more details.

 14 

 15    You should have received a copy of the GNU Lesser General Public

 16    License along with the GNU C Library; if not, see

 17    <http://www.gnu.org/licenses/>.  */

 18 

 19 #include <stdio.h>

 20 #include <stdlib.h>

 21 #include <unistd.h>

 22 #include <sysdep.h>

 23 #include "exit.h"

 24 

 25 #include "set-hooks.h"

 26 DEFINE_HOOK (__libc_atexit, (void))

 27 

 28 

 29 /* Call all functions registered with `atexit' and `on_exit',

 30    in the reverse of the order in which they were registered

 31    perform stdio cleanup, and terminate program execution with STATUS.  */

 32 void

 33 attribute_hidden

 34 __run_exit_handlers (int status, struct exit_function_list **listp,

 35              bool run_list_atexit)

 36 {

 37   /* We do it this way to handle recursive calls to exit () made by

 38      the functions registered with `atexit' and `on_exit'. We call

 39      everyone on the list and use the status value in the last

 40      exit (). */

 41   while (*listp != NULL)

 42     {

 43       struct exit_function_list *cur = *listp;

 44 

 45       while (cur->idx > 0)

 46     {

 47       const struct exit_function *const f =

 48         &cur->fns[--cur->idx];

 49       switch (f->flavor)

 50         {

 51           void (*atfct) (void);

 52           void (*onfct) (int status, void *arg);

 53           void (*cxafct) (void *arg, int status);

 54 

 55         case ef_free:

 56         case ef_us:

 57           break;

 58         case ef_on:

 59           onfct = f->func.on.fn;

 60 #ifdef PTR_DEMANGLE

 61           PTR_DEMANGLE (onfct);

 62 #endif

 63           onfct (status, f->func.on.arg);

 64           break;

 65         case ef_at:

 66           atfct = f->func.at;

 67 #ifdef PTR_DEMANGLE

 68           PTR_DEMANGLE (atfct);

 69 #endif

 70           atfct ();

 71           break;

 72         case ef_cxa:

 73           cxafct = f->func.cxa.fn;

 74 #ifdef PTR_DEMANGLE

 75           PTR_DEMANGLE (cxafct);

 76 #endif

 77           cxafct (f->func.cxa.arg, status);

 78           break;

 79         }

 80     }

 81 

 82       *listp = cur->next;

 83       if (*listp != NULL)

 84     /* Don't free the last element in the chain, this is the statically

 85        allocate element.  */

 86     free (cur);

 87     }

 88 

 89   if (run_list_atexit)

 90     RUN_HOOK (__libc_atexit, ());

 91 

 92   _exit (status);

 93 }

 94 

 95 

 96 void

 97 exit (int status)

 98 {

 99   __run_exit_handlers (status, &__exit_funcs, true);

100 }

101 libc_hidden_def (exit)

위의 원본 코드에서 알 수 있듯이 exit () 는atexit 등록된 함수를 실행한 다음에 _exit 함수,_exit는 프로세스의 모든 파일 설명자를 닫고 메모리와 다른 내부 핵 정리 함수를 정리합니다.그래서 exit()가 _까지 실행되면exit () 가 있을 때, 이전에 만든 라인이 실행을 중지합니다.이전에 내 머릿속에 존재했던'main 함수 종료'의 개념은 너무 추상적이었다. 그 뒤에 존재하는 것은 사실 하나의 동작 흐름이다.atexit가 등록한 함수를 실행하고 플러그인 흐름(stdin,stdout,stderr)을 갱신하며 파일 버퍼의 내용을 파일로 되돌려주고 프로세스의 모든 파일 설명자를 닫으며 메모리와 다른 내부 청소 함수를 정리한다.exit() 및_exit () 원본은 잘 연구해야 합니다.
다시 한 번 첫 번째 문장의atexit 해석을 돌이켜보면 다른 깊은 뜻이 있다.

좋은 웹페이지 즐겨찾기