程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> atexit注冊的函數是在main函數之後執行?

atexit注冊的函數是在main函數之後執行?

編輯:關於C語言

跟atexit函數相識已久,man手冊裡對atexit的解釋是這麼一段:

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

乍一看,就形成了這樣的印象:“哦,atexit函數就是來注冊一個函數A,使main函數退出後,要執行一下函數A,進程才會徹底over”。

直到工作中遇到一個段錯的bug,日志中發現,進程在執行atexit注冊過的函數時,main函數裡的線程依然在快活地運行,這種現象顛覆了我以往的認知,讓我不得不重新思考,atexit注冊的函數到底什麼時候執行?何為“退出main函數”?

先上一段簡單代碼:

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <pthread.h>
 
  bye(      printf(     sleep(     printf(  
  *do_thread(      (          printf(         sleep(   
  main(       
      pthread_create(&pid_t, NULL, ( * 
  }

上面的程序先用atexit注冊一個程序正常退出後的執行函數,再創建一線程用來不斷輸出信息,然後主線程執行exit;

運行程序會輸出什麼呢?

我一開始的猜測運行結果應該是:

before bye

after bye

或者是:

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

before bye

after bye

因為在我的理解中,bye()是在退出main函數之後執行,那時候,main函數裡創建的線程什麼的應該都不復存在了,代碼會清清靜靜地執行bye()函數。事實證明,我太想當然了。

上面程序實際運行結果是:

  --------------I
 --------------I
 --------------I
 --------------I
 --------------I
 --------------I
 --------------I
 --------------I
 --------------I
 --------------I
 after bye

為什麼在執行bye()的時候線程還在呢?

來看一下exit()函數的源碼:

    
     
     
   
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sysdep.h>
 #include 
 
 #include 
 DEFINE_HOOK (__libc_atexit, ( 
 
   
 
  __run_exit_handlers ( status,  exit_function_list **                     
    (*listp !=         exit_function_list *cur = * 
        (cur->idx >           exit_function * f =
         &cur->fns[--cur->        (f->             (*atfct) (            (*onfct) ( status,  *            (*cxafct) ( *arg,  
                                                 onfct = f->   
           onfct (status, f->                               atfct = f->   
                                cxafct = f->   
           cxafct (f->              
       *listp = cur->        (*listp !=      
   
     
   
 
 
 exit (    __run_exit_handlers (status, &__exit_funcs,   libc_hidden_def (exit)

從上面的源碼可以看出:exit()先是執行atexit注冊的函數,然後再執行_exit函數,_exit會關閉進程所有的文件描述符,清理內存以及其他一些內核清理函數。所以當exit()執行到_exit()的時候,之前創建的線程才會停止運行。之前我腦海裡存在的“退出main函數”的概念還是太抽象了,其背後存在的其實是一個動作流,會執行atexit注冊的函數,刷新流(stdin, stdout, stderr),把文件緩沖區的內容寫回文件,關閉進程所有的文件描述符,清理內存以及其他一些內核清理函數。exit()和_exit()源碼有待好好研究。

再次回首篇頭那一段atexit的解釋,別有一番深意。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved