#wait 1
在成都網(wǎng)站制作、成都網(wǎng)站設(shè)計中從網(wǎng)站色彩、結(jié)構(gòu)布局、欄目設(shè)置、關(guān)鍵詞群組等細(xì)微處著手,突出企業(yè)的產(chǎn)品/服務(wù)/品牌,幫助企業(yè)鎖定精準(zhǔn)用戶,提高在線咨詢和轉(zhuǎn)化,使成都網(wǎng)站營銷成為有效果、有回報的無錫營銷推廣。創(chuàng)新互聯(lián)公司專業(yè)成都網(wǎng)站建設(shè)十余年了,客戶滿意度97.8%,歡迎成都創(chuàng)新互聯(lián)客戶聯(lián)系。
#command ... ? ? ?
wait命令用來等待指令的指令,直到其執(zhí)行完畢后返回終端。該指令常用于shell腳本編程中,待指定的指令執(zhí)行完成后,才會繼續(xù)執(zhí)行后面的任務(wù)。該指令等待作業(yè)時,在作業(yè)標(biāo)識號前必須添加備份號"%"。 ?網(wǎng)頁鏈接? 學(xué)習(xí)linux
語法 ? ??
wait(參數(shù))
參數(shù)
進(jìn)程或作業(yè)標(biāo)示:指定進(jìn)程號或者作業(yè)號。如果wait后面不帶參數(shù),那么wait會阻塞當(dāng)前進(jìn)程的執(zhí)行,直至當(dāng)前進(jìn)程的所有子進(jìn)程都執(zhí)行結(jié)束后,才繼續(xù)執(zhí)行。
當(dāng)有多個子進(jìn)程的SIGCHLD信號到達(dá)父進(jìn)程的時候,如果父進(jìn)程用wait等待,那么父進(jìn)程在處理第一個達(dá)到的SIGCHLD信號的時候,其他的
SIGCHLD信號被堵塞,而且信號不被緩存,這樣就會導(dǎo)致信號丟失,這樣會產(chǎn)生很多的僵尸進(jìn)程。。解決辦法是父進(jìn)程用waitpid來等待子進(jìn)程信
號。。。
wait
1.1 簡介
wait函數(shù)所需頭文件:
#include sys/types.h
#include sys/wait.h
wait函數(shù)原型:
pid_t wait(int *status);
進(jìn)程一旦調(diào)用了
wait,就立即阻塞自己,由wait自動分析是否當(dāng)前進(jìn)程的某個子進(jìn)程已經(jīng)退出,如果讓它找到了這樣一個已經(jīng)變成僵尸的子進(jìn)程,wait就會收集這個子
進(jìn)程的信息,并把它徹底銷毀后返回;如果沒有找到這樣一個子進(jìn)程,wait就會一直阻塞在這里,直到有一個出現(xiàn)為止。
參數(shù)status用來保存 被收集進(jìn)程退出時的一些狀態(tài),它是一個指向int類型的指針。但如果我們對這個子進(jìn)程是如何死掉的毫不在意,只想把這個僵尸進(jìn)程消滅掉,(事實上絕大多數(shù) 情況下,我們都會這樣想),我們就可以設(shè)定這個參數(shù)為NULL,就象下面這樣:
pid = wait(NULL);
如果成 功,wait會返回被收集的子進(jìn)程的進(jìn)程ID,如果調(diào)用進(jìn)程沒有子進(jìn)程,調(diào)用就會失敗,此時wait返回-1,同時errno被置為ECHILD。
1.2 實戰(zhàn)
下面就讓我們用一個例子來實戰(zhàn)應(yīng)用一下wait調(diào)用,程序中用到了系統(tǒng)調(diào)用fork,如果你對此不大熟悉或已經(jīng)忘記了,請參考fork函數(shù)的使用。
/* wait1.c */
#include sys/types.h
#include sys/wait.h
#include unistd.h
#include stdlib.h
int main()
{
pid_t pc,pr;
pc = fork();
if (pc 0) /* 如果出錯 */
printf("error ocurred!\n");
else if (pc == 0) /* 如果是子進(jìn)程 */
{
printf("This is child process with pid of %d\n",getpid());
sleep(10); /* 睡眠10秒鐘 */
}
else /* 如果是父進(jìn)程 */
{
pr = wait(NULL); /* 在這里等待 */
printf("I catched a child process with pid of %d\n"),pr);
exit(0);
}
}
編譯并運行:
# cc wait1.c -o wait1
# ./wait1
#This is child process with pid of 1508I
#catched a child process with pid of 1508
可以明顯注意到,在第2行結(jié)果打印出來前有10秒鐘的等待時間,這就是我們設(shè)定的讓子進(jìn)程睡眠的時間,只有子進(jìn)程從睡眠中蘇醒過來,它才能正常退出,也就
才能被父進(jìn)程捕捉到。其實這里我們不管設(shè)定子進(jìn)程睡眠的時間有多長,父進(jìn)程都會一直等待下去,讀者如果有興趣的話,可以試著自己修改一下這個數(shù)值,看看會
出現(xiàn)怎樣的結(jié)果。
1.3 參數(shù)status
如果參數(shù)status的值不是NULL,wait就會把子進(jìn)程退出時的狀態(tài)取出并存入其中,這是一個整數(shù)值(int),指出了子進(jìn)程是正常退出
還是被非正常結(jié)束的(一個進(jìn)程也可以被其他進(jìn)程用信號結(jié)束),以及正常結(jié)束時的返回值,或被哪一個信號結(jié)束的等信息。由于這些信息被存放在一個整數(shù)的不同
二進(jìn)制位中,所以用常規(guī)的方法讀取會非常麻煩,人們就設(shè)計了一套專門的宏(macro)來完成這項工作,下面我們來學(xué)習(xí)一下其 中最常用的兩個:
1,WIFEXITED(status) 這個宏用來指出子進(jìn)程是否為正常退出的,如果是,它會返回一個非零值。
(請注意,雖然名字一樣,這里的參數(shù)status并不同于wait唯一的參數(shù)--指向整數(shù)的指針status,而是那個指針?biāo)赶虻恼麛?shù),切記不要搞混
了。)
2,WEXITSTATUS(status)
當(dāng)WIFEXITED返回非零值時,我們可以用這個宏來提取子進(jìn)程的返回值,如果子進(jìn)程調(diào)用exit(5)退出,WEXITSTATUS(status)
就會返回5;如果子進(jìn)程調(diào)用exit(7),WEXITSTATUS(status)就會返回7。請注意,如果進(jìn)程不是正常退出的,也就是
說,WIFEXITED返回0,這個值就毫無意義。
下面通過例子來實戰(zhàn)一下我們剛剛學(xué)到的內(nèi)容:
/* wait2.c */
#include sys/types.h
#include sys/wait.h
#include unistd.h
int main()
{
int status;
pid_t pc,pr;
pc = fork(); /*調(diào)用fork函數(shù)*/
if (pc 0) /* 如果出錯 */
printf("error ocurred!\n");
else if (pc == 0) /* 子進(jìn)程 */
{
printf("This is child process with pid of %d.\n",getpid());
exit(3); /* 子進(jìn)程返回3 */
}
else /* 父進(jìn)程 */
{
pr = wait(status);
if (WIFEXITED(status))
{
printf("the child process %d exit normally.\n",pr);
printf("the return code is %d.\n",WEXITSTATUS(status));
}
else /* 如果WIFEXITED返回零 */
printf("the child process %d exit abnormally.\n",pr);
}
}
編譯并運行:
# cc wait2.c -o wait2
# ./wait2
#This is child process with pid of 1538.
#the child process 1538 exit normally.
#the return code is 3.
#the child process 1538 exit abnormally.
父進(jìn)程準(zhǔn)確捕捉到了子進(jìn)程的返回值3,并把它打印了出來。
當(dāng)然,處理進(jìn)程退出狀態(tài)的宏并不止這兩個,但它們當(dāng)中的絕大部分在平時的編程中很少用到,就也不在這里浪費篇幅介紹了,有興趣的讀者可 以自己參閱Linux man pages去了解它們的用法。
waitpid
2.1 簡介
waitpid系統(tǒng)調(diào)用在Linux函數(shù)庫中的所需頭文件:
#include sys/types.h
#include sys/wait.h
waitpid系統(tǒng)調(diào)用在Linux函數(shù)庫中的原型是:
pid_t waitpid(pid_t pid,int *status,int options);
從本質(zhì)上講,系統(tǒng)調(diào)用waitpid和 wait的作用是完全相同的,但waitpid多出了兩個可由用戶控制的參數(shù)pid和options,從而為我們編程提供了另一種更靈活的方式。下面我們 就來詳細(xì)介紹一下這兩個參數(shù):
pid
從參數(shù)的名字pid和類型 pid_t中就可以看出,這里需要的是一個進(jìn)程ID。但當(dāng)pid取不同的值時,在這里有不同的意義。
pid0時,等待進(jìn)程ID等于 pid的子進(jìn)程,不管其它已經(jīng)有多少子進(jìn)程運行結(jié)束退出了,只要指定的子進(jìn)程還沒有結(jié)束,waitpid就會一直等下去。
pid=-1時,等待任何一個子進(jìn)程退出,沒有任何限制,此時waitpid和wait的作用一模一樣。
pid=0時,等待同一個進(jìn)程組中的任何子進(jìn)程,如果子進(jìn)程已經(jīng)加入了別的進(jìn)程組,waitpid不會對它做任何理睬。
pid-1時,等待一個指定進(jìn)程組中的任何子進(jìn)程,這個進(jìn)程組的ID等于pid的絕對值。
options
options提供了一些額外的選項來控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED兩個選項,這是兩個常數(shù),可以用"|"運算符把它們連接起來使用,比如:
ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);
如果我們不想使用它們,也可以把options設(shè)為0,如:
ret=waitpid(-1,NULL,0);
如果使用了 WNOHANG參數(shù)調(diào)用waitpid,如果沒有任何已終止的進(jìn)程,它也會立即返回,不會像wait那樣永遠(yuǎn)等下去。
而WUNTRACED參數(shù),如果子進(jìn)程進(jìn)入暫停執(zhí)行則馬上返回,但終止?fàn)顟B(tài)不予理睬。
看到這里,聰明的讀者可能已經(jīng)看出端倪了--wait不就是經(jīng)過包裝的waitpid嗎?沒錯,察看內(nèi)核源碼目錄/include/unistd.h文件349-352行就會發(fā)現(xiàn)以下程序段:
static inline pid_t wait(int * wait_stat){return waitpid(-1,wait_stat,0);}
2.2 返回值和錯誤
waitpid的返回值比wait稍微復(fù)雜一些,一共有3種情況:
當(dāng)正常返回的時候,waitpid返回收集到的子進(jìn)程的進(jìn)程ID;
如果設(shè)置了選項WNOHANG,而調(diào)用中waitpid發(fā)現(xiàn)沒有已退出的子進(jìn)程可收集,則返回0;
如果調(diào)用中出錯,則返回-1,這時errno會被設(shè)置成相應(yīng)的值以指示錯誤所在;
當(dāng)pid所指示的子進(jìn)程不存在,或此進(jìn)程存在,但不是調(diào)用進(jìn)程的子進(jìn)程,waitpid就會出錯返回,這時errno被設(shè)置為ECHILD;
/* waitpid.c */
#include sys/types.h
#include sys/wait.h
#include unistd.h
int main()
{
pid_t pc, pr;
pc = fork();
if (pc 0) /* 如果fork出錯 */
printf("Error occured on forking.\n");
else if (pc == 0) /* 如果是子進(jìn)程 */
{
sleep(10); /* 睡眠10秒 */
exit(0);
}
else /* 如果是父進(jìn)程 */
do
{
pr = waitpid(pc, NULL, WNOHANG); /* 使用了WNOHANG參數(shù),waitpid不會在這里等待 */
if (pr == 0) /* 如果沒有收集到子進(jìn)程 */
{
printf("No child exited\n");
sleep(1);
}
}
while (pr == 0); /* 沒有收集到子進(jìn)程,就回去繼續(xù)嘗試 */
if (pr == pc)
printf("successfully get child %d\n", pr);
else
printf("some error occured\n");
}
編譯并運行:
#gcc waitpid.c -o waitpid
#./waitpid
#No child exited
#No child exited
#No child exited
#No child exited
#No child exited
#No child exited
#No child exited
#No child exited
#No child exited
#No child exited
#successfully get child 1526
父進(jìn)程經(jīng)過10次失敗的嘗試之 后,終于收集到了退出的子進(jìn)程。
因為這只是一個例子程序,不便寫得太復(fù)雜,所以我們就讓父進(jìn)程和子進(jìn)程分別睡眠了10秒鐘和1秒鐘,代表它們分 別作了10秒鐘和1秒鐘的工作。父子進(jìn)程都有工作要做,父進(jìn)程利用工作的簡短間歇察看子進(jìn)程的是否退出,如退出就收集它。
進(jìn)程一旦調(diào)用了wait,就立即阻塞自己,由wait自動分析是否當(dāng)前進(jìn)程的某個子進(jìn)程已經(jīng)退出,如果讓它找到了這樣一個已經(jīng)變成僵尸的子進(jìn)程,wait 就會收集這個子進(jìn)程的信息, 并把它徹底銷毀后返回;如果沒有找到這樣一個子進(jìn)程,wait就會一直阻塞在這里,直到有一個出現(xiàn)為止。
#include unistd.h
#include signal.h
#include stdio.h
int pid1, pid2;
main()
{
int fd[2];
char outpipe[100],inpipe[100];
pipe(fd);
while((pid1=fork())==-1);
if(pid1==0) //子進(jìn)程1
{
lockf(fd[1],1,0);
sprintf(outpipe,"child 1 process is sending a message!");
write(fd[1],outpipe,50); //子進(jìn)程1寫數(shù)據(jù)到管道
sleep(5);
lockf(fd[1],0,0);
exit(0);
}
else //父進(jìn)程
{
while((pid2=fork())==-1); //創(chuàng)建子進(jìn)程2
if(pid2==0) //子進(jìn)程2執(zhí)行
{
lockf(fd[1],1,0); /*mutex*/
sprintf(outpipe,"child 2 process is sending a message!");
write(fd[1],outpipe,50); //子進(jìn)程2向管道寫數(shù)據(jù)
sleep(5);
lockf(fd[1],0,0);
exit(0);
}
else //父進(jìn)程
{
wait(0); //等待子進(jìn)程結(jié)束,那就是子進(jìn)程1先結(jié)束了,進(jìn)程1先創(chuàng)建的寫入數(shù)據(jù)后,延時5s就/結(jié)束了
read(fd[0],inpipe,50);//讀管道數(shù)據(jù)
printf("%s\n",inpipe);//輸出的是child 1 process is sending a message!
wait(0); ////////////////////////////再次等待進(jìn)程結(jié)束,這里等的就是進(jìn)程2.
read(fd[0],inpipe,50);//讀管道數(shù)據(jù)
printf("%s\n",inpipe);//這里輸出 child 2 process is sending a message!
exit(0);
}
}
}
fork()函數(shù)的作用是創(chuàng)建一個進(jìn)程。在應(yīng)用程序調(diào)用fork()函數(shù)后,會創(chuàng)建一個新的進(jìn)程,稱做子進(jìn)程,原來的進(jìn)程稱做父進(jìn)程。從這以后,運行的已經(jīng)是兩個進(jìn)程了,子進(jìn)程和父進(jìn)程都可以得到fork()的返回值。對于子進(jìn)程來說,fork()函數(shù)的返回值是0,對于父進(jìn)程來說,fork函數(shù)的返回的是子進(jìn)程的進(jìn)程號。如果創(chuàng)建進(jìn)程失敗,fork()函數(shù)會給父進(jìn)程返回-1,這也是判斷進(jìn)程是否創(chuàng)建成功的依據(jù)
wait是等待,等待前面的所有子進(jìn)程全部執(zhí)行完才繼續(xù)。這里p1=fork(),p2=fork()不是有調(diào)用到fork子進(jìn)程嗎
寫這個的目的是避免上面的還沒執(zhí)行完就開始執(zhí)行后續(xù)的程序了。
我舉個例子,你在執(zhí)行備份后刪除原文件操作,備份還沒進(jìn)行完,程序就開始刪除了。這樣就會出錯了。
當(dāng)然你這里后續(xù)沒有操作,wait只是在等待上面的全部做完然后退出整個程序。
wait 命令后面跟的參數(shù)是進(jìn)程的id,根據(jù)我的理解,wait是等待某進(jìn)程結(jié)束后再往下執(zhí)行腳本,如果wait后不跟參數(shù),就是等待以上所有進(jìn)程都執(zhí)行完后再往下執(zhí)行腳本。
按照你的意思,是要等待一段時間的,則應(yīng)該用sleep 命令,sleep就是用來延遲一段時間用的,將wait 300 改成sleep 300才正確。