1. exit函數(shù)
我們知道,進(jìn)程有五種正常終止:
1). 從main函數(shù)執(zhí)行return語句,如同調(diào)用exit一樣。
2). 調(diào)用exit。此函數(shù)有ISO C定義,其操作包括調(diào)用各中終止處理程序,然后關(guān)閉所有標(biāo)準(zhǔn)I/O流等。因?yàn)镮SO C并不處理文件描述符,多進(jìn)程以及作業(yè)控制,所以這一定義對UNIX系統(tǒng)是不完整的。
3). 調(diào)用_exit或_Exit。ISO C定義_Exit,其目的是為進(jìn)程提高一種無需運(yùn)行終止處理程序或信號處理程序而終止的方法。在UNIX系統(tǒng)中,_exit或_Exit是同義的,并不沖洗標(biāo)準(zhǔn)I/O流。_exit由exit調(diào)用。
4). 進(jìn)程的最后一個線程在啟動例程中執(zhí)行返回語句。但是,該線程的返回值不會用作進(jìn)程的返回值。而該進(jìn)程以終止?fàn)顟B(tài)0返回。
5). 最后一個線程調(diào)用pthead_exit,而該進(jìn)程以終止?fàn)顟B(tài)0返回。
三種異常終止
1). 調(diào)用abort
2). 接到一個信號并終止
3). 最后一個線程對取消請求做出響應(yīng)。
不管進(jìn)程如何終止,最后都會執(zhí)行內(nèi)核同一段代碼。這段代碼為相應(yīng)進(jìn)程關(guān)閉所有打開描述符,釋放它使用的存儲器等。
在任意一種情況下,終止進(jìn)程的父進(jìn)程都能用wait或waitpid函數(shù)取得其終止?fàn)顟B(tài)。在最后調(diào)用_exit時,內(nèi)核將退出狀態(tài)轉(zhuǎn)換為終止?fàn)顟B(tài)(termination status)。
如果父進(jìn)程在子進(jìn)程前終止,將如何?對于父進(jìn)程已經(jīng)終止的所有進(jìn)程,它們的父進(jìn)程都改變?yōu)閕nit進(jìn)程。我們稱這些進(jìn)程由init領(lǐng)養(yǎng)。在一個進(jìn)程終止時,內(nèi)核逐個堅(jiān)持所有活動進(jìn)程,以判斷它是否是正要終止進(jìn)程的子進(jìn)程,如果是,則將該進(jìn)程的父進(jìn)程ID改為1。只要init的子進(jìn)程終止,init會調(diào)用一個wait函數(shù)獲得其終止?fàn)顟B(tài)。
如果子進(jìn)程在父進(jìn)程之前終止,將如何?內(nèi)核為每個終止子進(jìn)程保存了一定量的信息,所以當(dāng)終止進(jìn)程的父進(jìn)程調(diào)用wait或waitpid函數(shù)時,可以得到這些信息。在UINX術(shù)語中,一個已經(jīng)終止、但是其父進(jìn)程尚未對其進(jìn)行善后處理(獲取終止子進(jìn)程的有關(guān)信息,釋放它仍占有的資源)的進(jìn)程被稱為僵死進(jìn)程(zombie)。ps命令將僵死進(jìn)程的狀態(tài)打印為Z。
2. wait和waitpid函數(shù)
當(dāng)一個進(jìn)程正?;虍惓=K止時,內(nèi)核就向其父進(jìn)程發(fā)送SIGCHLD信號。父進(jìn)程可以忽略該信號,或調(diào)用信號處理函數(shù)。調(diào)用wait或waitpid的進(jìn)程,會發(fā)生以下情況:
1). 如果其所有子進(jìn)程都在運(yùn)行,則該進(jìn)程阻塞
2). 如果一個子進(jìn)程已經(jīng)終止,正等待父進(jìn)程獲取其終止?fàn)顟B(tài),則取得該進(jìn)程的終止?fàn)顟B(tài)立即返回
3). 如果它沒有任何子進(jìn)程,則立即出錯返回。
#include <sys/wait.h>
#pid_t wait (int * statloc);
#pid_t waitpid (pid_t pid, int * statloc, int optins);
2.1. wait和waitpid函數(shù)區(qū)別
區(qū)別如下
1). 在一個子進(jìn)程終止前,wait使其調(diào)用者阻塞,而waitpid有一個選項(xiàng),可使調(diào)用者不阻塞。
2). waitpid并不等待在其調(diào)用之后的第一個終止子進(jìn)程,它有若干個選項(xiàng),可以控制它所等到的進(jìn)程。
3). 對于wait,其唯一的出錯是調(diào)用進(jìn)程沒有子進(jìn)程;對于waitpid,入股指定的進(jìn)程或進(jìn)程組不存在,或者參數(shù)pid指定的進(jìn)程不是調(diào)用進(jìn)程的子進(jìn)程都可能出錯。
4). Waitpid提供了wait沒有的三個功能:一是waitpid可等待一個特定的進(jìn)程;二是waitpid提供了一個waitpid的非阻塞版本;三是waitpid支持作業(yè)控制。
依據(jù)傳統(tǒng),這兩個函數(shù)返回的整型狀態(tài)字是由實(shí)現(xiàn)定義的。其中某些位表示退出狀態(tài)(正常返回),其它位表示信號編號(異常返回)。下表有四個互斥的宏。
WIFEXITED(status)
若為正常終止子進(jìn)程返回的狀態(tài),則為真。對于這種情況可以執(zhí)行WEXITSTATUS(status),取子進(jìn)程傳送給exit、_exit或_Exit參數(shù)的低8位。
WIFSIGNALED(status)
若為異常終止子進(jìn)程返回的狀態(tài),則為真(接到一個不捕捉的信號)。對于這種情況可以執(zhí)行WTERMSIG(status),取得子進(jìn)程終止的信號編號。
WIFSTOPPED(status)
若為當(dāng)前暫停子進(jìn)程返回的狀態(tài),則為真。對于這種情況可以執(zhí)行WSTOPSIG(status),取得子進(jìn)程暫停的信號編號。
WIFCONTINUED(status)
若在作業(yè)控制暫停后已經(jīng)繼續(xù)的子進(jìn)程返回的狀態(tài),則為真。僅用于waitpid。
對于waitpid函數(shù)中的pid參數(shù)的作用見下表:
pid == -1
等待任一子進(jìn)程。
pid > 0
等待其進(jìn)程ID與pid相等的子進(jìn)程
pid == 0
等待其組ID等于調(diào)用進(jìn)程組ID的任一的子進(jìn)程
pid < -1
等待其組ID等于pid絕對值的任一的子進(jìn)程
對于waitpid函數(shù)中的options參數(shù)的作用見下表:
WCONTINUED
若實(shí)現(xiàn)支持作業(yè)控制,那么由pid指定的任一子進(jìn)程在暫停后已經(jīng)繼續(xù),但是狀態(tài)沒報告,則返回其狀態(tài)
WNOHANG
若由pid指定的子進(jìn)程并不是立即可用的,則waitpid不阻塞,此時返回值為0
WUNTRACED
若實(shí)現(xiàn)支持作業(yè)控制,那么由pid指定的任一子進(jìn)程已經(jīng)處于暫停狀態(tài)并沒報告過,則返回其狀態(tài)
2.2. fork兩次可以避免僵死進(jìn)程
實(shí)例如下:
view plaincopy to clipboardprint?
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/wait.h>
int main ()
{
pid_t pid;
if((pid_t = fork()) < 0)
{
printf("fork error\n");
}
else if (pid == 0)
{
// 父進(jìn)程A的子進(jìn)程B
if((pid_t = fork()) < 0)
{
printf("fork error\n");
}
else if (pid > 0)
{
// 父進(jìn)程A的子進(jìn)程B退出
exit(0);
}
// 子進(jìn)程B的子進(jìn)程C繼續(xù)
sleep(2);
printf("second child, parent pid = %d\n", getpid());
// 子進(jìn)程B的子進(jìn)程C退出
exit(0);
}
// 父進(jìn)程A阻塞
if(waitpid(pid, NULL, 0) != pid)
{
printf("waitpid error\n");
}
//
exit(0);
}
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:
file:///D:/我的文檔/Linux/Process/進(jìn)程控制之exit和waitpid(wait)函數(shù)%20-%20緣起宇軒閣%20-%20CSDN博客.mht