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