7.3 进程终止
7.3 進程終止
有8種方式使進程終止(termination),其中5中為正常終止,他們是:
l? 從main返回;
l? 調用exit;
l? 調用_exit或_Exit;
l? 最后一個線程從其啟動例程返回;
l? 最后一個線程調用pthread_exit;
異常終止有3種方式,他們是:
l? 調用abort;
l? 接收一個信號并終止;
l? 最后一個線程對取消請求做出響應。
?
上節提及的起動例程是這樣編寫的,使得從main返回后立即調用exit函數。如果將啟動例程以C代碼形式表示(實際上該例程常常用匯編語言編寫),則它調用main函數的形式可能是:
exit( main(argc, argv) );
7.3.1 exit和_ exit函數
有三個函數用于正常終止一個程序:_exit 和 _Exit 立即進入內核,exit 則先執行一些 清理處理(包括調用執行各終止處理程序,關閉所有標準 I/O 流等),然后進入內核。
#include <stdlib.h>void exit(int s t a t u s) ;
void _Exit(int status);
#include <unistd.h>
void _exit (ints t a t u s) ;
我們將在8 . 5節中討論這三個函數對其他進程,例如終止進程的父、子進程的影響。
使用不同頭文件的原因是:exit和_Exi是由ANSI C說明的,而_ exit則是由POSIX . 1說明的。
由于歷史原因, exit函數總是執行一個標準I/O庫的清除關閉操作:為所有打開流調用fclose函數。回憶5.5節,這造成緩存中的所有數據都被刷新(寫到文件上)。
三個exit函數都帶一個整型參數,稱之為終止狀態(exit status)。大多數UNIX shell都提供檢查一個進程終止狀態的方法。如果(a)若調用這些函數時不帶終止狀態,或(b)main執行了一個無返回值的return語句,或(c)main沒有聲明返回類型為整型,則該進程的終止狀態是末定義的。
但是,若main的返回類型是整型,并且main執行到最后一條語句時返回(隱式返回),那么該進程的終止狀態為0。
main函數返回一個整型值與用該值調用exit是等價的。于是在main函數中
exit(0);等價于return 0;
這就意味著,下列經典性的C語言程序:
#include <stdio.h>
main ()
{
printf ("hello, world \n");
}
是不完整的,因為main函數沒有使用return語句返回(隱式返回),它在返回到C的起動例程時并沒有返回一個值(終止狀態)。另外,若使用:
return ( 0 ) ;
或者
exit ( 0 );
則向執行此程序的進程(常常是一個s h e l l進程)返回終止狀態0。另外,main函數的說明實際上應當是:
int main(void)
對上述程序進行編譯,然后運行,則可見其終止碼(echo $?)是隨機的。如果在不同的系統上編譯該程序,我們很可能得到不同的終止碼,這取決與main函數返回時棧和寄存器的內容。
將main說明為返回一個整型以及用exit代替return,對某些C編譯程序和UNIX lint ( 1 )程序而言會產生不必要的警告信息,因為這些編譯程序并不了解main中的exit與return語句的作用相同。警告信息可能是“ control reaches end of nonvoid f u n c t i o n(控制到達非v o i d函數的結束處)”。避開這種警告信息的一種方法是:在main中使用return語句而不是exit。但是這樣做的結果是不能用U N I X的g r e p公用程序來找出程序中所有的exit調用。另外一個解決方法是將main說明為返回v o i d而不是i n t,然后仍舊調用exit。這也避開了編譯程序的警告,但從程序設計角度看卻并不正確。本章將main表示為返回一個整型,因為這是ANSI C和POSIX . 1所定義的。我們將不理會編譯程序不必要的警告。
下一章將了解進程如何使程序執行,如何等待執行該程序的進程完成,然后取得其終止狀態。
7.3.2 atexit函數
按照ISO C的規定,一個進程可以登記多至3 2個函數,這些函數將由exit自動調用。我們稱這些函數為終止處理程序(exit handler),并用atexit函數來登記這些函數。
#include <stdlib.h>
int atexit(void (*func) ( v o i d ) ) ;
返回:若成功則為0,若出錯則為非0
其中, atexit的參數是一個函數地址,當調用此函數時無需向它傳送任何參數,也不期望它返回一個值。exit以登記這些函數的相反順序調用它們。同一函數如若登記多次,則也被調用多次。
終止處理程序這一機制由ANSI C最新引進。S V R 4和4 . 3 + B S D都提供這種機制。系統V的早期版本和4 . 3 B S D則都不提供此機制。為了確定一個給定的平臺支持的最大終止處理程序數,可以使用sysconf函數。
根據ISO C和POSIX . 1,exit首先調用各終止處理程序,然后按需多次調用f c l o s e,關閉所有打開流。POSIX.1擴展了ISO c標準,它指定如若程序調用exec函數族中的任一函數,則將清除所有已安裝的終止處理程序。圖7 - 1顯示了一個C程序是如何起動的,以及它終止的各種方式。
圖7-1 一個C程序是如何起動和終止的(啟動的_exit也可以為_Exit)
注意,內核使程序執行的唯一方法是調用一個exec函數。進程自愿終止的唯一方法是顯式或隱式地(調用exit )調用_ exit或_Exit。進程也可非自愿地由一個信號使其終止(圖7 - 1中沒有顯示)。
實例
程序7 - 2說明了如何使用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)
perror("can not register my_exit2");
if (atexit(my_exit1) != 0)
perror("can not register my_exit2");
if (atexit(my_exit1) != 0)
perror("can not register my_exit2");
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");
}
執行程序7 - 2產生:
main is done
first exit handler
first exit handler
second exit handler
????? 終止處理程序每登記一次,就會被調用一次。在上述程序中,第一個終止處理程序被登記兩次,所以也會被調用兩次。注意,在main中沒有調用exit,而是用了return語句。
轉載于:https://www.cnblogs.com/shaoguangleo/archive/2011/10/11/2806002.html
總結
- 上一篇: 基于PHP+小程序(MINA框架)+My
- 下一篇: 编译安装KVM虚拟化技术