當(dāng)前位置:首頁(yè) > 嵌入式 > 嵌入式教程
[導(dǎo)讀]在Linux中創(chuàng)建一個(gè)新進(jìn)程的惟一方法是使用fork()函數(shù)。fork()函數(shù)是Linux中一個(gè)非常重要的函數(shù),和讀者以往遇到的函數(shù)有一些區(qū)別,因?yàn)樗雌饋?lái)執(zhí)行一次卻返回兩個(gè)值。難道一個(gè)函數(shù)真的能返回兩個(gè)值嗎?希望讀者能認(rèn)真地學(xué)習(xí)這一部分的內(nèi)容。

7.2Linux進(jìn)程控制編程1.fork()

在Linux中創(chuàng)建一個(gè)新進(jìn)程的惟一方法是使用fork()函數(shù)。fork()函數(shù)是Linux中一個(gè)非常重要的函數(shù),和讀者以往遇到的函數(shù)有一些區(qū)別,因?yàn)樗雌饋?lái)執(zhí)行一次卻返回兩個(gè)值。難道一個(gè)函數(shù)真的能返回兩個(gè)值嗎?希望讀者能認(rèn)真地學(xué)習(xí)這一部分的內(nèi)容。

(1)fork()函數(shù)說(shuō)明。

fork()函數(shù)用于從已存在的進(jìn)程中創(chuàng)建一個(gè)新進(jìn)程。新進(jìn)程稱為子進(jìn)程,而原進(jìn)程稱為父進(jìn)程。使用fork()函數(shù)得到的子進(jìn)程是父進(jìn)程的一個(gè)復(fù)制品,它從父進(jìn)程處繼承了整個(gè)進(jìn)程的地址空間,包括進(jìn)程上下文、代碼段、進(jìn)程堆棧、內(nèi)存信息、打開(kāi)的文件描述符、信號(hào)控制設(shè)定、進(jìn)程優(yōu)先級(jí)、進(jìn)程組號(hào)、當(dāng)前工作目錄、根目錄、資源限制和控制終端等,而子進(jìn)程所獨(dú)有的只有它的進(jìn)程號(hào)、資源使用和計(jì)時(shí)器等。

因?yàn)樽舆M(jìn)程幾乎是父進(jìn)程的完全復(fù)制,所以父子兩個(gè)進(jìn)程會(huì)運(yùn)行同一個(gè)程序。因此需要用一種方式來(lái)區(qū)分它們,并使它們照此運(yùn)行,否則,這兩個(gè)進(jìn)程不可能做不同的事。

實(shí)際上是在父進(jìn)程中執(zhí)行fork()函數(shù)時(shí),父進(jìn)程會(huì)復(fù)制出一個(gè)子進(jìn)程,而且父子進(jìn)程的代碼從fork()函數(shù)的返回開(kāi)始分別在兩個(gè)地址空間中同時(shí)運(yùn)行。從而兩個(gè)進(jìn)程分別獲得其所屬fork()的返回值,其中在父進(jìn)程中的返回值是子進(jìn)程的進(jìn)程號(hào),而在子進(jìn)程中返回0。因此,可以通過(guò)返回值來(lái)判定該進(jìn)程是父進(jìn)程還是子進(jìn)程。

同時(shí)可以看出,使用fork()函數(shù)的代價(jià)是很大的,它復(fù)制了父進(jìn)程中的代碼段、數(shù)據(jù)段和堆棧段里的大部分內(nèi)容,使得fork()函數(shù)的系統(tǒng)開(kāi)銷比較大,而且執(zhí)行速度也不是很快。

(2)fork()函數(shù)語(yǔ)法。

表7.2列出了fork()函數(shù)的語(yǔ)法要點(diǎn)。

表7.2 fork()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<sys/types.h>//提供類型pid_t的定義
#include<unistd.h>

函數(shù)原型

pid_tfork(void)

函數(shù)返回值

0:子進(jìn)程

子進(jìn)程ID(大于0的整數(shù)):父進(jìn)程

-1:出錯(cuò)

(3)fork()函數(shù)使用實(shí)例。

/*fork.c*/

#include<sys/types.h>

#include<unistd.h>

#include<stdio.h>

#include<stdlib.h>

intmain(void)

{

pid_tresult;

/*調(diào)用fork()函數(shù)*/

result=fork();

/*通過(guò)result的值來(lái)判斷fork()函數(shù)的返回情況,首先進(jìn)行出錯(cuò)處理*/

if(result==-1)

{

printf("Forkerrorn");

}

elseif(result==0)/*返回值為0代表子進(jìn)程*/

{

printf("Thereturnedvalueis%dn

Inchildprocess!!nMyPIDis%dn",result,getpid());

}

else/*返回值大于0代表父進(jìn)程*/

{

printf("Thereturnedvalueis%dn

Infatherprocess!!nMyPIDis%dn",result,getpid());

}

returnresult;

}

將可執(zhí)行程序下載到目標(biāo)板上,運(yùn)行結(jié)果如下所示:

$arm-linux-gccfork.c–ofork(或者修改Makefile)

$./fork

Thereturnedvalueis76/*在父進(jìn)程中打印的信息*/

Infatherprocess!!

MyPIDis75

Thereturnedvalueis:0/*在子進(jìn)程中打印的信息*/

Inchildprocess!!

MyPIDis76

從該實(shí)例中可以看出,使用fork()函數(shù)新建了一個(gè)子進(jìn)程,其中的父進(jìn)程返回子進(jìn)程的PID,而子進(jìn)程的返回值為0。

(4)函數(shù)使用注意點(diǎn)。

fork()函數(shù)使用一次就創(chuàng)建一個(gè)進(jìn)程,所以若把fork()函數(shù)放在了ifelse判斷語(yǔ)句中則要小心,不能多次使用fork()函數(shù)。

小知識(shí)

由于fork()完整地復(fù)制了父進(jìn)程的整個(gè)地址空間,因此執(zhí)行速度是比較慢的。為了加快fork()的執(zhí)行速度,有些UNIX系統(tǒng)設(shè)計(jì)者創(chuàng)建了vfork()。vfork()也能創(chuàng)建新進(jìn)程,但它不產(chǎn)生父進(jìn)程的副本。它是通過(guò)允許父子進(jìn)程可訪問(wèn)相同物理內(nèi)存從而偽裝了對(duì)進(jìn)程地址空間的真實(shí)拷貝,當(dāng)子進(jìn)程需要改變內(nèi)存中數(shù)據(jù)時(shí)才復(fù)制父進(jìn)程。這就是著名的“寫(xiě)操作時(shí)復(fù)制”(copy-on-write)技術(shù)。

現(xiàn)在很多嵌入式Linux系統(tǒng)的fork()函數(shù)調(diào)用都采用vfork()函數(shù)的實(shí)現(xiàn)方式,實(shí)際上uClinux所有的多進(jìn)程管理都通過(guò)vfork()來(lái)實(shí)現(xiàn)。

2.exec函數(shù)族

(1)exec函數(shù)族說(shuō)明。

fork()函數(shù)是用于創(chuàng)建一個(gè)子進(jìn)程,該子進(jìn)程幾乎復(fù)制了父進(jìn)程的全部?jī)?nèi)容,但是,這個(gè)新創(chuàng)建的進(jìn)程如何執(zhí)行呢?這個(gè)exec函數(shù)族就提供了一個(gè)在進(jìn)程中啟動(dòng)另一個(gè)程序執(zhí)行的方法。它可以根據(jù)指定的文件名或目錄名找到可執(zhí)行文件,并用它來(lái)取代原調(diào)用進(jìn)程的數(shù)據(jù)段、代碼段和堆棧段,在執(zhí)行完之后,原調(diào)用進(jìn)程的內(nèi)容除了進(jìn)程號(hào)外,其他全部被新的進(jìn)程替換了。另外,這里的可執(zhí)行文件既可以是二進(jìn)制文件,也可以是Linux下任何可執(zhí)行的腳本文件。

在Linux中使用exec函數(shù)族主要有兩種情況。

n 當(dāng)進(jìn)程認(rèn)為自己不能再為系統(tǒng)和用戶做出任何貢獻(xiàn)時(shí),就可以調(diào)用exec函數(shù)族中的任意一個(gè)函數(shù)讓自己重生。

n 如果一個(gè)進(jìn)程想執(zhí)行另一個(gè)程序,那么它就可以調(diào)用fork()函數(shù)新建一個(gè)進(jìn)程,然后調(diào)用exec函數(shù)族中的任意一個(gè)函數(shù),這樣看起來(lái)就像通過(guò)執(zhí)行應(yīng)用程序而產(chǎn)生了一個(gè)新進(jìn)程(這種情況非常普遍)。

(2)exec函數(shù)族語(yǔ)法。

實(shí)際上,在Linux中并沒(méi)有exec()函數(shù),而是有6個(gè)以exec開(kāi)頭的函數(shù),它們之間語(yǔ)法有細(xì)微差別,本書(shū)在下面會(huì)詳細(xì)講解。

下表7.3列舉了exec函數(shù)族的6個(gè)成員函數(shù)的語(yǔ)法。

表7.3 exec函數(shù)族成員函數(shù)語(yǔ)法

所需頭文件

#include<unistd.h>

函數(shù)原型

intexecl(constchar*path,constchar*arg,...)

intexecv(constchar*path,char*constargv[])

intexecle(constchar*path,constchar*arg,...,char*constenvp[])

intexecve(constchar*path,char*constargv[],char*constenvp[])

intexeclp(constchar*file,constchar*arg,...)

intexecvp(constchar*file,char*constargv[])

函數(shù)返回值

-1:出錯(cuò)

這6個(gè)函數(shù)在函數(shù)名和使用語(yǔ)法的規(guī)則上都有細(xì)微的區(qū)別,下面就可執(zhí)行文件查找方式、參數(shù)表傳遞方式及環(huán)境變量這幾個(gè)方面進(jìn)行比較。

n 查找方式。

讀者可以注意到,表7.3中的前4個(gè)函數(shù)的查找方式都是完整的文件目錄路徑,而最后2個(gè)函數(shù)(也就是以p結(jié)尾的兩個(gè)函數(shù))可以只給出文件名,系統(tǒng)就會(huì)自動(dòng)按照環(huán)境變量“$PATH”所指定的路徑進(jìn)行查找。

n 參數(shù)傳遞方式。

exec函數(shù)族的參數(shù)傳遞有兩種方式:一種是逐個(gè)列舉的方式,而另一種則是將所有參數(shù)整體構(gòu)造指針數(shù)組傳遞。

在這里是以函數(shù)名的第5位字母來(lái)區(qū)分的,字母為“l”(list)的表示逐個(gè)列舉參數(shù)的方式,其語(yǔ)法為char*arg;字母為“v”(vertor)的表示將所有參數(shù)整體構(gòu)造指針數(shù)組傳遞,其語(yǔ)法為*constargv[]。讀者可以觀察execl()、execle()、execlp()的語(yǔ)法與execv()、execve()、execvp()的區(qū)別。它們具體的用法在后面的實(shí)例講解中會(huì)具體說(shuō)明。

這里的參數(shù)實(shí)際上就是用戶在使用這個(gè)可執(zhí)行文件時(shí)所需的全部命令選項(xiàng)字符串(包括該可執(zhí)行程序命令本身)。要注意的是,這些參數(shù)必須以NULL表示結(jié)束,如果使用逐個(gè)列舉方式,那么要把它強(qiáng)制轉(zhuǎn)化成一個(gè)字符指針,否則exec將會(huì)把它解釋為一個(gè)整型參數(shù),如果一個(gè)整型數(shù)的長(zhǎng)度char*的長(zhǎng)度不同,那么exec函數(shù)就會(huì)報(bào)錯(cuò)。

n 環(huán)境變量。

exec函數(shù)族可以默認(rèn)系統(tǒng)的環(huán)境變量,也可以傳入指定的環(huán)境變量。這里以“e”(environment)結(jié)尾的兩個(gè)函數(shù)execle()和execve()就可以在envp[]中指定當(dāng)前進(jìn)程所使用的環(huán)境變量。

表7.4是對(duì)這4個(gè)函數(shù)中函數(shù)名和對(duì)應(yīng)語(yǔ)法的小結(jié),主要指出了函數(shù)名中每一位所表明的含義,希望讀者結(jié)合此表加以記憶。

表7.4 exec函數(shù)名對(duì)應(yīng)含義

前4位

統(tǒng)一為:exec

第5位

l:參數(shù)傳遞為逐個(gè)列舉方式

execl、execle、execlp

v:參數(shù)傳遞為構(gòu)造指針數(shù)組方式

execv、execve、execvp

第6位

e:可傳遞新進(jìn)程環(huán)境變量

execle、execve

p:可執(zhí)行文件查找方式為文件名

execlp、execvp

(3)exec使用實(shí)例。

下面的第一個(gè)示例說(shuō)明了如何使用文件名的方式來(lái)查找可執(zhí)行文件,同時(shí)使用參數(shù)列表的方式。這里用的函數(shù)是execlp()。

/*execlp.c*/

#include<unistd.h>

#include<stdio.h>

#include<stdlib.h>

intmain()

{

if(fork()==0)

{

/*調(diào)用execlp()函數(shù),這里相當(dāng)于調(diào)用了"ps-ef"命令*/

if((ret=execlp("ps","ps","-ef",NULL))<0)

{

printf("Execlperrorn");

}

}

}

在該程序中,首先使用fork()函數(shù)創(chuàng)建一個(gè)子進(jìn)程,然后在子進(jìn)程里使用execlp()函數(shù)。讀者可以看到,這里的參數(shù)列表列出了在shell中使用的命令名和選項(xiàng)。并且當(dāng)使用文件名進(jìn)行查找時(shí),系統(tǒng)會(huì)在默認(rèn)的環(huán)境變量PATH中尋找該可執(zhí)行文件。讀者可將編譯后的結(jié)果下載到目標(biāo)板上,運(yùn)行結(jié)果如下所示:

$./execlp

PIDTTYUidSizeStateCommand

1root1832Sinit

2root0S[keventd]

3root0S[ksoftirqd_CPU0]

4root0S[kswapd]

5root0S[bdflush]

6root0S[kupdated]

7root0S[mtdblockd]

8root0S[khubd]

35root2104S/bin/bash/usr/etc/rc.local

36root2324S/bin/bash

41root1364S/sbin/inetd

53root14260S/Qtopia/qtopia-free-1.7.0/bin/qpe-qws

54root11672Squicklauncher

65root0S[usb-storage-0]

66root0S[scsi_eh_0]

83root2020Rps-ef

$env

……

PATH=/Qtopia/qtopia-free-1.7.0/bin:/usr/bin:/bin:/usr/sbin:/sbin

……

此程序的運(yùn)行結(jié)果與在shell中直接鍵入命令“ps-ef”是一樣的,當(dāng)然,在不同系統(tǒng)的不同時(shí)刻都可能會(huì)有不同的結(jié)果。

接下來(lái)的示例使用完整的文件目錄來(lái)查找對(duì)應(yīng)的可執(zhí)行文件。注意目錄必須以“/”開(kāi)頭,否則將其視為文件名。

/*execl.c*/

#include<unistd.h>

#include<stdio.h>

#include<stdlib.h>

intmain()

{

if(fork()==0)

{

/*調(diào)用execl()函數(shù),注意這里要給出ps程序所在的完整路徑*/

if(execl("/bin/ps","ps","-ef",NULL)<0)

{

printf("Execlerrorn");

}

}

}

同樣下載到目標(biāo)板上運(yùn)行,運(yùn)行結(jié)果同上例。

下面的示例利用函數(shù)execle(),將環(huán)境變量添加到新建的子進(jìn)程中,這里的“env”是查看當(dāng)前進(jìn)程環(huán)境變量的命令,如下所示:

/*execle.c*/

#include<unistd.h>

#include<stdio.h>

#include<stdlib.h>

intmain()

{

/*命令參數(shù)列表,必須以NULL結(jié)尾*/

char*envp[]={"PATH=/tmp","USER=david",NULL};

if(fork()==0)

{

/*調(diào)用execle()函數(shù),注意這里也要指出env的完整路徑*/

if(execle("/usr/bin/env","env",NULL,envp)<0)

{

printf("Execleerrorn");

}

}

}

下載到目標(biāo)板后的運(yùn)行結(jié)果如下所示:

$./execle

PATH=/tmp

USER=sunq

最后一個(gè)示例使用execve()函數(shù),通過(guò)構(gòu)造指針數(shù)組的方式來(lái)傳遞參數(shù),注意參數(shù)列表一定要以NULL作為結(jié)尾標(biāo)識(shí)符。其代碼和運(yùn)行結(jié)果如下所示:

#include<unistd.h>

#include<stdio.h>

#include<stdlib.h>

intmain()

{

/*命令參數(shù)列表,必須以NULL結(jié)尾*/

char*arg[]={"env",NULL};

char*envp[]={"PATH=/tmp","USER=david",NULL};

if(fork()==0)

{

if(execve("/usr/bin/env",arg,envp)<0)

{

printf("Execveerrorn");

}

}

}

下載到目標(biāo)板后的運(yùn)行結(jié)果如下所示:

$./execve

PATH=/tmp

USER=david

(4)exec函數(shù)族使用注意點(diǎn)。

在使用exec函數(shù)族時(shí),一定要加上錯(cuò)誤判斷語(yǔ)句。exec很容易執(zhí)行失敗,其中最常見(jiàn)的原因有:

n 找不到文件或路徑,此時(shí)errno被設(shè)置為ENOENT;

n 數(shù)組argv和envp忘記用NULL結(jié)束,此時(shí)errno被設(shè)置為EFAULT;

n 沒(méi)有對(duì)應(yīng)可執(zhí)行文件的運(yùn)行權(quán)限,此時(shí)errno被設(shè)置為EACCES。

小知識(shí)

事實(shí)上,這6個(gè)函數(shù)中真正的系統(tǒng)調(diào)用只有execve(),其他5個(gè)都是庫(kù)函數(shù),它們最終都會(huì)調(diào)用execve()這個(gè)系統(tǒng)調(diào)用。

3.exit()和_exit()

(1)exit()和_exit()函數(shù)說(shuō)明。

exit()和_exit()函數(shù)都是用來(lái)終止進(jìn)程的。當(dāng)程序執(zhí)行到exit()或_exit()時(shí),進(jìn)程會(huì)無(wú)條件地停止剩下的所有操作,清除包括PCB在內(nèi)的各種數(shù)據(jù)結(jié)構(gòu),并終止本進(jìn)程的運(yùn)行。但是,這兩個(gè)函數(shù)還是有區(qū)別的,這兩個(gè)函數(shù)的調(diào)用過(guò)程如圖7.4所示。

圖7.4exit和_exit函數(shù)流程圖

從圖中可以看出,_exit()函數(shù)的作用是:直接使進(jìn)程停止運(yùn)行,清除其使用的內(nèi)存空間,并清除其在內(nèi)核中的各種數(shù)據(jù)結(jié)構(gòu);exit()函數(shù)則在這些基礎(chǔ)上做了一些包裝,在執(zhí)行退出之前加了若干道工序。exit()函數(shù)與_exit()函數(shù)最大的區(qū)別就在于exit()函數(shù)在調(diào)用exit系統(tǒng)之前要檢查文件的打開(kāi)情況,把文件緩沖區(qū)中的內(nèi)容寫(xiě)回文件,就是圖中的“清理I/O緩沖”一項(xiàng)。

由于在Linux的標(biāo)準(zhǔn)函數(shù)庫(kù)中,有一種被稱作“緩沖I/O(bufferedI/O)”操作,其特征就是對(duì)應(yīng)每一個(gè)打開(kāi)的文件,在內(nèi)存中都有一片緩沖區(qū)。每次讀文件時(shí),會(huì)連續(xù)讀出若干條記錄,這樣在下次讀文件時(shí)就可以直接從內(nèi)存的緩沖區(qū)中讀取;同樣,每次寫(xiě)文件的時(shí)候,也僅僅是寫(xiě)入內(nèi)存中的緩沖區(qū),等滿足了一定的條件(如達(dá)到一定數(shù)量或遇到特定字符等),再將緩沖區(qū)中的內(nèi)容一次性寫(xiě)入文件。

這種技術(shù)大大增加了文件讀寫(xiě)的速度,但也為編程帶來(lái)了一些麻煩。比如有些數(shù)據(jù),認(rèn)為已經(jīng)被寫(xiě)入文件中,實(shí)際上因?yàn)闆](méi)有滿足特定的條件,它們還只是被保存在緩沖區(qū)內(nèi),這時(shí)用_exit()函數(shù)直接將進(jìn)程關(guān)閉,緩沖區(qū)中的數(shù)據(jù)就會(huì)丟失。因此,若想保證數(shù)據(jù)的完整性,就一定要使用exit()函數(shù)。

(2)exit()和_exit()函數(shù)語(yǔ)法。

表7.5列出了exit()和_exit()函數(shù)的語(yǔ)法規(guī)范。

表7.5 exit()和_exit()函數(shù)族語(yǔ)法

所需頭文件

exit:#include<stdlib.h>

_exit:#include<unistd.h>

函數(shù)原型

exit:voidexit(intstatus)

_exit:void_exit(intstatus)

函數(shù)傳入值

status是一個(gè)整型的參數(shù),可以利用這個(gè)參數(shù)傳遞進(jìn)程結(jié)束時(shí)的狀態(tài)。一般來(lái)說(shuō),0表示正常結(jié)束;其他的數(shù)值表示出現(xiàn)了錯(cuò)誤,進(jìn)程非正常結(jié)束。
在實(shí)際編程時(shí),可以用wait()系統(tǒng)調(diào)用接收子進(jìn)程的返回值,從而針對(duì)不同的情況進(jìn)行不同的處理

(3)exit()和_exit()使用實(shí)例。

這兩個(gè)示例比較了exit()和_exit()兩個(gè)函數(shù)的區(qū)別。由于printf()函數(shù)使用的是緩沖I/O方式,該函數(shù)在遇到“n”換行符時(shí)自動(dòng)從緩沖區(qū)中將記錄讀出。示例中就是利用這個(gè)性質(zhì)來(lái)進(jìn)行比較的。以下是示例1的代碼:

/*exit.c*/

#include<stdio.h>

#include<stdlib.h>

intmain()

{

printf("Usingexit...n");

printf("Thisisthecontentinbuffer");

exit(0);

}

$./exit

Usingexit...

Thisisthecontentinbuffer$

讀者從輸出的結(jié)果中可以看到,調(diào)用exit()函數(shù)時(shí),緩沖區(qū)中的記錄也能正常輸出。

以下是示例2的代碼:

/*_exit.c*/

#include<stdio.h>

#include<unistd.h>

intmain()

{

printf("Using_exit...n");

printf("Thisisthecontentinbuffer");/*加上回車(chē)符之后結(jié)果又如何*/

_exit(0);

}

$./_exit

Using_exit...

$

讀者從最后的結(jié)果中可以看到,調(diào)用_exit()函數(shù)無(wú)法輸出緩沖區(qū)中的記錄。

小知識(shí)

在一個(gè)進(jìn)程調(diào)用了exit()之后,該進(jìn)程并不會(huì)立刻完全消失,而是留下一個(gè)稱為僵尸進(jìn)程(Zombie)的數(shù)據(jù)結(jié)構(gòu)。僵尸進(jìn)程是一種非常特殊的進(jìn)程,它已經(jīng)放棄了幾乎所有的內(nèi)存空間,沒(méi)有任何可執(zhí)行代碼,也不能被調(diào)度,僅僅在進(jìn)程列表中保留一個(gè)位置,記載該進(jìn)程的退出狀態(tài)等信息供其他進(jìn)程收集,除此之外,僵尸進(jìn)程不再占有任何內(nèi)存空間。

4.wait()和waitpid()

(1)wait()和waitpid()函數(shù)說(shuō)明。

wait()函數(shù)是用于使父進(jìn)程(也就是調(diào)用wait()的進(jìn)程)阻塞,直到一個(gè)子進(jìn)程結(jié)束或者該進(jìn)程接到了一個(gè)指定的信號(hào)為止。如果該父進(jìn)程沒(méi)有子進(jìn)程或者他的子進(jìn)程已經(jīng)結(jié)束,則wait()就會(huì)立即返回。

waitpid()的作用和wait()一樣,但它并不一定要等待第一個(gè)終止的子進(jìn)程,它還有若干選項(xiàng),如可提供一個(gè)非阻塞版本的wait()功能,也能支持作業(yè)控制。實(shí)際上wait()函數(shù)只是waitpid()函數(shù)的一個(gè)特例,在Linux內(nèi)部實(shí)現(xiàn)wait()函數(shù)時(shí)直接調(diào)用的就是waitpid()函數(shù)。

(2)wait()和waitpid()函數(shù)格式說(shuō)明。

表7.6列出了wait()函數(shù)的語(yǔ)法規(guī)范。

表7.6 wait()函數(shù)族語(yǔ)法

所需頭文件

#include<sys/types.h>
#include<sys/wait.h>

函數(shù)原型

pid_twait(int*status)

函數(shù)傳入值

這里的status是一個(gè)整型指針,是該子進(jìn)程退出時(shí)的狀態(tài)
·status若不為空,則通過(guò)它可以獲得子進(jìn)程的結(jié)束狀態(tài)
另外,子進(jìn)程的結(jié)束狀態(tài)可由Linux中一些特定的宏來(lái)測(cè)定

函數(shù)返回值

成功:已結(jié)束運(yùn)行的子進(jìn)程的進(jìn)程號(hào)
失?。?1

表7.7列出了waitpid()函數(shù)的語(yǔ)法規(guī)范。

表7.7 waitpid()函數(shù)語(yǔ)法

所需頭文件

#include<sys/types.h>
#include<sys/wait.h>

函數(shù)原型

pid_twaitpid(pid_tpid,int*status,intoptions)

續(xù)表

函數(shù)傳入值

Pid

pid>0:只等待進(jìn)程ID等于pid的子進(jìn)程,不管已經(jīng)有其他子進(jìn)程運(yùn)行結(jié)束退出了,只要指定的子進(jìn)程還沒(méi)有結(jié)束,waitpid()就會(huì)一直等下去

pid=-1:等待任何一個(gè)子進(jìn)程退出,此時(shí)和wait()作用一樣

pid=0:等待其組ID等于調(diào)用進(jìn)程的組ID的任一子進(jìn)程

pid<-1:等待其組ID等于pid的絕對(duì)值的任一子進(jìn)程

status

同wait()

options

WNOHANG:若由pid指定的子進(jìn)程不立即可用,則waitpid()不阻塞,此時(shí)返回值為0

WUNTRACED:若實(shí)現(xiàn)某支持作業(yè)控制,則由pid指定的任一子進(jìn)程狀態(tài)已暫停,且其狀態(tài)自暫停以來(lái)還未報(bào)告過(guò),則返回其狀態(tài)

0:同wait(),阻塞父進(jìn)程,等待子進(jìn)程退出

函數(shù)返回值

正常:已經(jīng)結(jié)束運(yùn)行的子進(jìn)程的進(jìn)程號(hào)

使用選項(xiàng)WNOHANG且沒(méi)有子進(jìn)程退出:0

調(diào)用出錯(cuò):-1

3)waitpid()使用實(shí)例。

由于wait()函數(shù)的使用較為簡(jiǎn)單,在此僅以waitpid()為例進(jìn)行講解。本例中首先使用fork()創(chuàng)建一個(gè)子進(jìn)程,然后讓其子進(jìn)程暫停5s(使用了sleep()函數(shù))。接下來(lái)對(duì)原有的父進(jìn)程使用waitpid()函數(shù),并使用參數(shù)WNOHANG使該父進(jìn)程不會(huì)阻塞。若有子進(jìn)程退出,則waitpid()返回子進(jìn)程號(hào);若沒(méi)有子進(jìn)程退出,則waitpid()返回0,并且父進(jìn)程每隔一秒循環(huán)判斷一次。該程序的流程圖如圖7.5所示。

圖7.5waitpid示例程序流

該程序源代碼如下所示:

/*waitpid.c*/

#include<sys/types.h>

#include<sys/wait.h>

#include<unistd.h>

#include<stdio.h>

#include<stdlib.h>

intmain()

{

pid_tpc,pr;

pc=fork();

if(pc<0)

{

printf("Errorforkn");

}

elseif(pc==0)/*子進(jìn)程*/

{

/*子進(jìn)程暫停5s*/

sleep(5);

/*子進(jìn)程正常退出*/

exit(0);

}

else/*父進(jìn)程*/

{

/*循環(huán)測(cè)試子進(jìn)程是否退出*/

do

{

/*調(diào)用waitpid,且父進(jìn)程不阻塞*/

pr=waitpid(pc,NULL,WNOHANG);

/*若子進(jìn)程還未退出,則父進(jìn)程暫停1s*/

if(pr==0)

{

printf("Thechildprocesshasnotexitedn");

sleep(1);

}

}while(pr==0);

/*若發(fā)現(xiàn)子進(jìn)程退出,打印出相應(yīng)情況*/

if(pr==pc)

{

printf("Getchildexitcode:%dn",pr);

}

else

{

printf("Someerroroccured.n");

}

}

}

將該程序交叉編譯,下載到目標(biāo)板后的運(yùn)行結(jié)果如下所示:

$./waitpid

Thechildprocesshasnotexited

Thechildprocesshasnotexited

Thechildprocesshasnotexited

Thechildprocesshasnotexited

Thechildprocesshasnotexited

Getchildexitcode:75

可見(jiàn),該程序在經(jīng)過(guò)5次循環(huán)之后,捕獲到了子進(jìn)程的退出信號(hào),具體的子進(jìn)程號(hào)在不同的系統(tǒng)上會(huì)有所區(qū)別。

讀者還可以嘗試把“pr=waitpid(pc,NULL,WNOHANG);”這句改為“pr=waitpid(pc,NULL,0);”或者“pr=wait(NULL);”,運(yùn)行的結(jié)果為:

$./waitpid

Getchildexitcode:76

可見(jiàn),在上述兩種情況下,父進(jìn)程在調(diào)用waitpid()或wait()之后就將自己阻塞,直到有子進(jìn)程退出為止。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車(chē)的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車(chē)技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車(chē)工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車(chē)。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車(chē) 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉