進程等待的基礎概念
進程等待就是爲了同步父進程和子進程,如把運算放到子進程,賦值放到父進程,可能需要讓父進程等待子進程運算結束.一個進程
在終止時會關閉所有的文件描述符,釋放在用戶空間分配的內存,但他的PCB還保留着,內核在其中保存了一些信息:如果是正常終
止則保存着退出狀態,如果是異常退出則保存着導致該進程終止的信號是哪個. 這個進程的父進程可以調用wait或waitpid獲取這
些信息,然後徹底消除掉這個進程。我們知道一個進程的退出狀態可以在shall中用特殊變量 $?查看,因爲shell是它的父進程,當它終止時
Shell調用wait或waitpid得到它的退出狀態同時徹底清除這個進程。
當一個進程正常或異常終止時,內核就向父進程發送一個SIGCHLD信號。因爲子進程終止是一個異步時間,所以發生這種信號發生
也是內核向父進程發的異步通知。父進程可以選擇忽略該信號,或者提供一個該信號發生時既被調用執行的函數。對於這種信號的系
統默認 動作是忽略它。 而父進程如果需要處理掉子進程就要調用wait和waitpid命令.
進程的三種基本狀態
進程在運行中不斷地改變其運行狀態。通常,一個運行進程必須具有以下三種基本狀態。
就緒狀態:當進程已分配到除CPU以外的所有必要的資源,只要獲得處理機便可立即執行,這時的進程狀態稱爲就緒狀態。
執行狀態:當進程已獲得處理機,其程序正在處理機上執行,此時的進程狀態稱爲執行狀態。
阻塞狀態:正在執行的進程,由於等待某個事件發生而無法執行時,便放棄處理機而處於阻塞狀態。引起進程阻塞的事件可有多
種,例如,等待I/O完成、申請緩衝區不能滿足、等待信件(信號)等。
父進程調用wait和waitpid函數後
如果其所有子進程都還在運行,則阻塞.
如果一個子進程已終止,正等待父進程獲取其終止狀態,則取得該子進程的終止態立即返回.
如果它沒有任何子進程,則立即出錯返回.
wait/waitpid函數
頭文件:#include<sys/tpes.h>
#include<sys/wait.h>
wait函數:pid_t wait(int* status)
返回值: 成功返回被等待進程pid,失敗返回-1.
參數:輸出型參數,獲取子進程退出的狀態不關心設置空.如果進程由於接收到SIGCHLD而調用wait,則會期望wait會立即返回.但如果
在任意時刻調用wait,則進程可能阻塞.在一個子進程終止前,wait使其調用者阻塞,而waitpid有一個選項,可使調用者不阻塞.如果
status不是一個空指針,則終止進程的終止狀態就存放它所指的單元內。 如果不關心終止狀態,則可將該參數設爲空指針.
waitpid函數:pid_t waitpid(pid_t pid,int *status,int options);
返回值:
1當正常返回時waitpid返回手機的子進程的進程ID
2.如果設置了選項WNOHANG,而調用中waitpid發現沒有退出的子進程可手機,賊返回0.
3.如果調用出錯返回-1
4.當pid所指示的子進程不存在,或此進程存在,但不是調用進程的子進程waitpid就會出錯返回,這是errno被設置爲ECHILD參數:
1.pid
pid = -1,等待任意個子進程
pid > 0,等待其進程ID與PID相等的子進程
pid = 0 等待其組ID等於調用進程組ID的任意意個子進程
pid < -1 等待其組ID等於PID絕對值的任意子進程2.status:
WIFEXITED: 若爲正常終止子進程的方法返回狀態賊爲真.
WEXITSTATUS:若WIFEXITED,提取子進程的退出碼.3.options
WNOHANG:若pid指定的子進程還沒有結束,則waitpid()函數返回0,不予以等待
若正常結束,則返回該子進程ID.(這裏就是我上面說的waitpid的特殊選項)
相關代碼:
阻塞等待
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
int main()
{
pid_t pid;
pid = fork();
if(pid < 0)
{
printf("%s fork error\n",__FUNCTION__);
return 1;
}
else if(pid == 0)
{
//子進程
printf("this is child,pid is:%d\n",getpid());
sleep(5);
exit(257);
}
else
{
int status = 0;
pid_t ret = waitpid(-1,&status,0);// wait 5s
printf("this is test for wait\n");
if(WIFEXITED(status)&&ret == pid)
printf("wait child 5s success,child return num is:%d\n",WEXITSTATUS(status));
else
{
printf("wait child failed,return \n");
return 1;
}
}
}
非阻塞等待
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
int main()
{
pid_t pid;
pid = fork();
if(pid < 0)
{
printf("%sfork error\n",__FUNCTION__);
return 1;
}
else if(pid == 0)
{
//child
printf("child is run,pid is: %d\n",getpid());
sleep(5);
exit(1);
}
else
{
int status = 0;
pid_t ret = 0;
do
{
ret = waitpid(-1,&status,WNOHANG);
printf("father do other thing\n");
if(ret == 0)
printf("child is runing\n");
sleep(1);
}while(ret == 0);
if(WIFEXITED(status)&& ret == pid)
printf("wait child 5s success,child return cod is:%d\n",WEXITSTATUS(status));
else{
printf("wait child failed,return\n");
return 1;
}
}
return 0;
}