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