Linux---創建、等待、終止進程

進程創建
父進程通過 fork(), vfork() 函數創建子進程
fork()測試代碼:

#include<stdio.h>
#include<unistd.h>

int main()
{
    printf("Before:pid is %d\n",getpid());

    pid_t pid = fork();//創建子進程
    if(pid < 0)
    {
        perror("fork");
    }
    printf("After:pid is %d,fork return %d\n",getpid(),pid);
    sleep(1);
    return 0;
}

測試結果:
這裏寫圖片描述
這裏輸出了三行結果。進程13417先打印Before,然後再打印After,而進程13418只打印了一條After,沒有打印Before,這是爲什麼?如下圖所示:
這裏寫圖片描述
fork()之前父進程獨立運行,fork()之後,父子兩個執行流分別執行。(即fork後,父子都從fork之後開始執行)需要注意的是,fork()之後,誰先執行完全取決於調度器。

由上面的示例可以看出,fork有兩個返回值,成功時,子進程返回0.父進程返回子進程的pid;失敗返回-1
fork後父子代碼共享,數據寫時拷貝(即父子共享一塊代碼,如果不再寫入時,數據也是共享的。但當任意一方試圖寫入時,便以寫實拷貝的方式各自保存一份副本)。

fork失敗的原因1.內存不夠。我們知道,創建進程需要給他分配相應的系統資源,而內存是有限的,如果內存不夠就會導致不能給新建的進程分配資源,因而創建失敗。2.進程太多,佔用着資源而沒有釋放,也會導致創建失敗。

vfork和fork的區別在於
1.vfork父子進程共用同一個地址空間,而fork子進程具有獨立的地址空間
2.vfork保證子進程先運行,在它調用exit或_exit後,父進程才能被調度運行。
來看下面的例子:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

int data = 10;
int main()
{
    pid_t pid = vfork();
    if(pid < 0)
    {
        perror("fork");
    }
    else if(pid == 0)//子進程
    {
        sleep(1);
        data = 20;
        printf("child data is %d\n",data);
        exit(0);
        //return 0;
    }
    else//父進程
    {
        printf("father data is %d\n",data);
    }
    return 0;
}

結果:
這裏寫圖片描述
可以看出,子進程直接改變了父進程的變量值,因爲子進程在父進程的地址空間運行。

上述代碼如果將子進程的退出方式改爲return 0,就會出現段錯誤,程序異常終止。
這裏寫圖片描述
因爲用return 0返回,main函數的棧幀已經釋放,父進程從vfork之後開始運行,但棧幀已經銷燬,就會出現訪問出錯。

進程等待

子進程退出時,父進程通過wait()和waitpid()函數來獲取子進程退出信息(畢竟你派給子進程的任務,得知道他完成的咋樣啊),如果父進程不回收,子進程就會變成殭屍狀態,進而導致內存泄露(殭屍進程刀槍不入,即使是殺人不眨眼的kill -9也無能爲力,因爲誰也沒有辦法殺死一個已經死去的進程)。

pid_t  wait(int* status)
返回值:
       成功時返回被等待進程的pid,失敗返回-1.
參數:
      輸出型參數,獲取子進程退出信息,不關心設置爲NULL
pid_t waitpid(pid_t pid,int* status,int options)
返回值:
      正常,返回等待子進程的pid;
      設置了WNOHANG選項,調用中waitpid發現沒有子進程要等,返回0;
      失敗返回-1,error會被設置成相應值,以指出錯誤所在。
參數:
     pid:
          pid = -1,等待任意一個子進程
          pid > 0,等待其進程id與pid相等的子進程
     status:
         WIFEXITED(status):查看進程是否正退出
         WEXITSTATUS(status):產看進程退出碼
     options:
         WNOHANG:設置了這個選項,非阻塞式的等待(若pid指定子   進程沒有結束,函數返回0,不予以等待,正常結束,返回子進程pid)

測試代碼:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>

int main()
{
    pid_t pid = fork();//創建子進程
    if(pid < 0)
    {
        perror("fork");
        exit(1);
    }
    if(pid == 0)//子進程
    {
        printf("pid: %d,ppid: %d\n",getpid(),getppid());
        sleep(10);
        exit(10);
    }
    else//父進程
    {
        int status;
        int ret = wait(&status);//父進程等子進程退出
        if(ret > 0)//異常退出
        {
            printf("sig code: %d\n",status & 0x7F);
        }
        if(ret > 0 && (status & 0x7F) == 0)//正常退出
        {
            printf("child exit code: %d\n",(status>>8) & 0xFF);
        }
    }
    return 0;
}

測試結果:
這裏寫圖片描述
10秒後輸出child退出信息
這裏寫圖片描述
通過在另一個終端發送2號信號來終止這個進程,此時異常退出,輸出退出碼。

進程終止

Linux下,進程正常退出方式:
1.在main函數中使用了return返回(return返回後把控制權交給了調用函數)
2.調用exit()或_exit()函數(exit()之後將控制權交給系統)

異常退出:
1.進程收到操作系統發來的某個信號來終止程序。
2.調用abort函數

無論哪種方式退出,最後都會執行內核中的同一段代碼,這段代碼用來關閉進程已打開的文件描述符和所佔用的系統資源。

exit函數和_exit函數:

void exit(int status);

exit最後也會調用_exit,但在調用之前,還做了其他工作:
這裏寫圖片描述
由上圖可以看出,_exit直接使進程停止運行,釋放其所佔有的系統資源,而exit在此基礎上做了一些包裝,終止前檢查該進程打開過哪些文件,將文件緩衝區內容寫回文件。

發佈了56 篇原創文章 · 獲贊 13 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章