Linux系統編程——進程的控制:結束進程、等待進程結束,linux進程

來源:互聯網
上載者:User

Linux系統編程——進程的控制:結束進程、等待進程結束,linux進程
結束進程

首先,我們回顧一下 C 語言中 continue, break, return 的作用:

continue: 結束本次迴圈

break: 跳出整個迴圈,或跳出 switch() 語句

return: 結束當前函數


而我們可以通過 exit() 或 _exit() 來結束當前進程。


所需標頭檔:

#include <stdlib.h> 


void exit(int value);

功能:

結束調用此函數的進程。

參數:

status:返回給父進程的參數(低 8 位有效),至於這個參數是多少根據需要來填寫。

返回值:


所需標頭檔:

#include <unistd.h>


void _exit(int value);

功能:

結束調用此函數的進程。

參數:

status:返回給父進程的參數(低 8 位有效),至於這個參數是多少根據需要來填寫。

返回值:


exit() 和 _exit() 函數功能和用法是一樣的,無非時所包含的標頭檔不一樣,還有的區別就是:exit()屬於標準庫函數,_exit()屬於系統調用函數。


下面的例子驗證調用 exit() 函數,會重新整理 I/O 緩衝區(關於緩衝區的更多詳情,請看《淺談標準I/O緩衝區》):

#include <stdio.h>#include <stdlib.h>#include <unistd.h>int main(int argc, char *argv[]){printf("hi, mike, you are so good"); // 列印,沒有分行符號"\n"exit(0);      // 結束進程,標準庫函數,重新整理緩衝區,printf()的內容能列印出來// _exit(0);  // 結束進程,系統調用函數,printf()的內容不會顯示到螢幕while(1);// 不讓程式結束return 0;}

運行結果如下:



上面的例子,結束進程的時候改為調用 _exit(),代碼如下:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>int main(int argc, char *argv[]){printf("hi, mike, you are so good"); // 列印,沒有分行符號"\n"//exit(0);      // 結束進程,標準庫函數,重新整理緩衝區,printf()的內容能列印出來_exit(0);  // 結束進程,系統調用函數,printf()的內容不會顯示到螢幕while(1);// 不讓程式結束return 0;}

printf() 的內容是不會顯示出來的,運行結果如下:



接下來,我們一起驗證一下結束函數( return )和結束進程( exit() )的區別。


測試代碼如下:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>void fun(){sleep(2);return;  // 結束 fun() 函數while(1);}int main(int argc, char *argv[]){fun();printf("after fun\n");while(1);// 不讓程式結束return 0;}

運行結果如下:



通過上面的運行結果得知,return 的作用只是結束調用 return 的所在函數,只要這個函數不是主函數( main() ),只要主函數沒有結束,return 並不能結束進程


我們將上面例子 fun() 裡的 return 改為 exit():

#include <stdio.h>#include <stdlib.h>#include <unistd.h>void fun(){sleep(2);exit(0);  // 結束當前進程while(1);}int main(int argc, char *argv[]){fun();printf("after fun\n");while(1);// 不讓程式結束return 0;}

exit() 是可以結束 fun() 所在的進程,即可讓程式結束運行,結果圖如下:



等待進程結束

當一個進程正常或異常終止時,核心就向其父進程發送 SIGCHLD 訊號,相當於告訴父親他哪個兒子掛了,而父進程可以通過 wait() 或 waitpid() 函數等待子進程結束,擷取子進程結束時的狀態,同時回收他們的資源(相當於,父親聽聽死去兒子的遺言同時好好安葬它)。


wait() 和 waitpid() 函數的功能一樣,區別在於,wait() 函數會阻塞,waitpid() 可以設定不阻塞,waitpid() 還可以指定等待哪個子進程結束。


所需標頭檔:

#include <sys/types.h>

#include <sys/wait.h>


pid_t wait(int *status);

功能:

等待任意一個子進程結束,如果任意一個子進程結束了,此函數會回收該子進程的資源(資源主要指核心進程式控制制塊結構體的資源,如,回收其進程號,讓別的進程可以重用此號碼)。


調用 wait() 函數的進程會掛起(阻塞),直到它的一個子進程退出或收到一個不能被忽視的訊號時才被喚醒(相當於繼續往下執行)。


若調用進程沒有子進程,該函數立即返回;若它的子進程已經結束,該函數同樣會立即返回,並且會回收那個早已結束進程的資源。


所以,wait()函數的主要功能為回收已經結束子進程的資源。


參數:

status: 進程退出時的狀態資訊。


如果參數 status 的值不是 NULL,wait() 就會把子進程退出時的狀態取出並存入其中,這是一個整數值(int),指出了子進程是正常退出還是被非正常結束的。


這個退出資訊在一個 int 中包含了多個欄位,直接使用這個值是沒有意義的,我們需要用宏定義取出其中的每個欄位


下面我們來學習一下其中最常用的兩個宏定義,取出子進程的退出資訊:

WIFEXITED(status)

如果子進程是正常終止的,取出的欄位值非零。

WEXITSTATUS(status)

返回子進程的退出狀態,退出狀態儲存在 status 變數的 8~16 位。在用此宏前應先用宏 WIFEXITED 判斷子進程是否正常退出,正常退出才可以使用此宏。


返回值:

成功:已經結束子進程的進程號

失敗:-1


從本質上講,系統調用 waitpid() 和 wait() 的作用是完全相同的,但 waitpid() 多出了兩個可由使用者控制的參數 pid 和 options,從而為我們編程提供了另一種更靈活的方式。


pid_t waitpid(pid_t pid, int *status, int options);

功能:

等待子進程終止,如果子進程終止了,此函數會回收子進程的資源。

參數:

pid: 參數 pid 的值有以下幾種類型:

pid > 0

等待進程 ID 等於 pid 的子進程。

pid = 0

等待同一個進程組中的任何子進程,如果子進程已經加入了別的進程組,waitpid 不會等待它。

pid = -1

等待任一子進程,此時 waitpid 和 wait 作用一樣。

pid < -1

等待指定進程組中的任何子進程,這個進程組的 ID 等於 pid 的絕對值。


status: 進程退出時的狀態資訊。和 wait() 用法一樣。


options: options 提供了一些額外的選項來控制 waitpid()。

0:

同 wait(),阻塞父進程,等待子進程退出。

WNOHANG;

沒有任何已經結束的子進程,則立即返回。

WUNTRACED:

如果子進程暫停了則此函數馬上返回,並且不予以理會子進程的結束狀態。(由於涉及到一些跟蹤調試方面的知識,加之極少用到,這裡就不多費筆墨了,有興趣的讀者可以自行查閱相關材料)

返回值:

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


當正常返回的時候,waitpid() 返回收集到的已經子進程的進程號;


如果設定了選項 WNOHANG,而調用中 waitpid() 發現沒有已退出的子進程可等待,則返回 0;


如果調用中出錯,則返回 -1,這時 errno 會被設定成相應的值以指示錯誤所在,如:當 pid 所對應的子進程不存在,或此進程存在,但不是調用進程的子進程,waitpid() 就會出錯返回,這時 errno 被設定為 ECHILD;


測試例子:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>int main(int argc, char *argv[]){pid_t pid;pid = fork(); // 建立進程if( pid < 0 ){ // 出錯perror("fork");exit(0);}if( pid == 0 ){// 子進程int i = 0;for(i=0;i<5;i++){printf("this is son process\n");sleep(1);}_exit(2); // 子進程退出,數字 2 為子進程退出的狀態}else if( pid > 0){ // 父進程int status = 0;// 等待子進程結束,回收子進程的資源// 此函數會阻塞// status 某個欄位儲存子進程調用 _exit(2) 的 2,需要用宏定義取出wait(&status); // waitpid(-1, &status, 0); // 和 wait() 沒區別,0:阻塞// waitpid(pid, &status, 0); // 指定等待進程號為 pid 的子進程, 0 阻塞// waitpid(pid, &status, WNOHANG); // WNOHANG:不阻塞if(WIFEXITED(status) != 0){ // 子進程是否正常終止printf("son process return %d\n", WEXITSTATUS(status));}printf("this is father process\n");}return 0;}

運行結果如下:



本教程範例程式碼下載請點此。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.