歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

linux進程(fork,waitpid)

對於進程的一生可以用一些形象的比喻作一個小小的總結:

隨著一句fork,一個新進程呱呱落地,但它這時只是老進程的一個克隆。

然後隨著exec,新進程脫胎換骨,離家獨立,開始了為人民服務的職業生涯。

人有生老病死,進程也一樣,它可以是自然死亡,即運行到main函數的最後一個”}”,從容地離我們而去;也可以是自殺,自殺有2種方式,一種是調用 exit函數,一種是在main函數內使用return,無論哪一種方式,它都可以留下遺書,放在返回值裡保留下來;它還甚至能可被謀殺,被其它進程通過另外一些方式結束他的生命。

進程死掉以後,會留下一具僵屍,wait和waitpid充當了殓屍工,把僵屍推去火化,使其最終歸於無形。

在linux中wait系統調用一文中介紹了其中的一個殓屍工wait, 下面介紹另一個waitpid,這個貌似復雜些。

waitpid函數原型:

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

#include<sys/wait.h>

pid_twaitpid(pid_tpid,int*status,intoptions);

從本質上講,系統調用waitpid和wait的作用是完全相同的,但waitpid多出了兩個可由用戶控制的參數pid和options,從而為我們編程提供了另一種更靈活的方式。下面我們就來詳細介紹一下這兩個參數:

pid

從參數的名字pid和類型pid_t中就可以看出,這裡需要的是一個進程ID。但當pid取不同的值時,在這裡有不同的意義。

1. pid>0時,只等待進程ID等於pid的子進程,不管其它已經有多少子進程運行結束退出了,只要指定的子進程還沒有結束,waitpid就會一直等下去。

2. pid=-1時,等待任何一個子進程退出,沒有任何限制,此時waitpid和wait的作用一模一樣。

3. pid=0時,等待同一個進程組中的任何子進程,如果子進程已經加入了別的進程組,waitpid不會對它做任何理睬。

4. pid<-1時,等待一個指定進程組中的任何子進程,這個進程組的ID等於pid的絕對值。

options

options提供了一些額外的選項來控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED兩個選項,這是兩個常數,可以用”|”運算符把它們連接起來使用,比如:

ret=waitpid(-1,NULL,WNOHANG|WUNTRACED);

如果我們不想使用它們,也可以把options設為0,如:

ret=waitpid(-1,NULL,0);

如果使用了WNOHANG參數調用waitpid,即使沒有子進程退出,它也會立即返回,不會像wait那樣永遠等下去。

而WUNTRACED參數,用於跟蹤調試,極少用到,就不說了。

查看linux源代碼 unistd.h 我們會發現,其實 wait 就是經過包裝的 waitpid:

staticinlinepid_twait(int*wait_stat)

{

returnwaitpid(-1,wait_stat,0);

}

waitpid的返回值比wait稍微復雜一些,一共有3種情況:

1. 當正常返回的時候,waitpid返回收集到的子進程的進程ID;

2. 如果設置了選項WNOHANG,而調用中waitpid發現沒有已退出的子進程可收集,則返回0;

3. 如果調用中出錯,則返回-1,這時errno會被設置成相應的值以指示錯誤所在;

當pid所指示的子進程不存在,或此進程存在,但不是調用進程的子進程,waitpid就會出錯返回,這時errno被設置為ECHILD;

下面看一個簡單的例子:

下載:waitpid.c

/* waitpid.c */

#include<sys/types.h>

#include<sys/wait.h>

#include<unistd.h>

#include<stdio.h>

int main()

{

pid_t pc,pr;

pc=fork();

if (pc<0)/* fork錯誤*/

{

printf("fork error\n");

exit(1);

}

else if(pc==0)/*在子進程中*/

{

sleep(10);

exit(0);

}

else

{

do {/* 使用了WNOHANG參數,waitpid不會在這裡等待 */

pr=waitpid(pc,NULL,WNOHANG);

if (pr==0)

{

printf("No child exit\n");

sleep(1);

}

}while (pr==0);

if (pr==pc)

printf("successfully get child %d\n",pr);

else

printf("wait child error\n");

}

return 0;

}

編譯並運行:

$ gcc -o waitpid waitpid.c

$ ./waitpid

No child exit

No child exit

No child exit

No child exit

No child exit

No child exit

No child exit

No child exit

No child exit

No child exit

successfully get child 4607

父進程經過10次失敗的嘗試之後,終於收集到了退出的子進程。父進程和子進程分別睡眠了10秒鐘和1秒鐘,代表它們分別作了10秒鐘和1秒鐘的工作。父子進程都有工作要做,父進程利用工作的簡短間歇察看子進程的是否退出,如退出就收集它。

Copyright © Linux教程網 All Rights Reserved