操作系統—進程等待

進程等待的基礎概念

進程等待就是爲了同步父進程和子進程,如把運算放到子進程,賦值放到父進程,可能需要讓父進程等待子進程運算結束.一個進程
在終止時會關閉所有的文件描述符,釋放在用戶空間分配的內存,但他的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;
}
發佈了78 篇原創文章 · 獲贊 34 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章