日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

【Linux系统编程】特殊进程之僵尸进程

發布時間:2024/4/24 linux 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Linux系统编程】特殊进程之僵尸进程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

00. 目錄

文章目錄

    • 00. 目錄
    • 01. 僵尸進程概述
    • 02. 僵尸進程案例
    • 03. 避免僵尸進程
    • 04. 附錄

01. 僵尸進程概述

進程已運行結束,但進程的占用的資源未被回收,這樣的進程稱為僵尸進程

在每個進程退出的時候,內核釋放該進程所有的資源、包括打開的文件、占用的內存等。 但是仍然為其保留一定的信息,這些信息主要主要指進程控制塊的信息(包括進程號、退出狀態、運行時間等)。直到父進程通過 wait() 或 waitpid() 來獲取其狀態并釋放。這樣就會導致一個問題,如果進程不調用wait() 或 waitpid() 的話, 那么保留的那段信息就不會釋放,其進程號就會一直被占用,但是系統所能使用的進程號是有限的,如果大量的產生僵尸進程,將因為沒有可用的進程號而導致系統不能產生新的進程.此即為僵尸進程的危害,應當避免。

子進程已運行結束,父進程未調用 wait() 或 waitpid() 函數回收子進程的資源是子進程變為僵尸進程的原因。

02. 僵尸進程案例

測試代碼:

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>int main(void) {pid_t pid = -1;pid = fork();if (-1 == pid){perror("fork"); goto err0;}else if (0 == pid){printf("I am child process %d\n", getpid());exit(0);}sleep(200);return 0; err0:return 1; }

測試結果:

我們另啟一個終端,查看進程的狀態,有哪些是僵尸進程:

或者

ps -ef | grep defunct ,后面尖括號里是 defunct 的都是僵尸進程。

03. 避免僵尸進程

3.1 避免僵尸進程的方法

  • 最簡單的方法,父進程通過 wait() 和 waitpid() 等函數等待子進程結束,但是,這會導致父進程掛起。

  • 如果父進程要處理的事情很多,不能夠掛起,通過 signal() 函數人為處理信號 SIGCHLD , 只要有子進程退出自動調用指定好的回調函數,因為子進程結束后, 父進程會收到該信號 SIGCHLD ,可以在其回調函數里調用 wait() 或 waitpid() 回收。關于信號的更詳細用法,請看《信號中斷處理》。

測試代碼:

#include <stdio.h> #include <unistd.h> #include <errno.h> #include <stdlib.h> #include <signal.h> #include <sys/wait.h>void sig_child(int signo) {pid_t pid; //處理僵尸進程, -1 代表等待任意一個子進程, WNOHANG代表不阻塞while( (pid = waitpid(-1, NULL, WNOHANG)) > 0 ){printf("child %d terminated.\n", pid);} }int main() {pid_t pid;// 創建捕捉子進程退出信號// 只要子進程退出,觸發SIGCHLD,自動調用sig_child()signal(SIGCHLD, sig_child);pid = fork(); // 創建進程if (pid < 0){ // 出錯perror("fork error:");exit(1);}else if(pid == 0){ // 子進程printf("I am child process,pid id %d.I am exiting.\n",getpid());exit(0);}else if(pid > 0){ // 父進程sleep(2); // 保證子進程先運行printf("I am father, i am exited\n\n");system("ps -ef | grep defunct"); // 查看有沒有僵尸進程}return 0; }

測試結果:

  • 如果父進程不關心子進程什么時候結束,那么可以用signal(SIGCHLD, SIG_IGN)通知內核,自己對子進程的結束不感興趣,父進程忽略此信號,那么子進程結束后,內核會回收, 并不再給父進程發送信號。關于信號的更詳細用法。

測試代碼如下:

#include <stdio.h> #include <unistd.h> #include <errno.h> #include <stdlib.h> #include <signal.h>int main() {pid_t pid;// 忽略子進程退出信號的信號// 那么子進程結束后,內核會回收, 并不再給父進程發送信號signal(SIGCHLD, SIG_IGN);pid = fork(); // 創建進程if (pid < 0){ // 出錯perror("fork error:");exit(1);}else if(pid == 0){ // 子進程printf("I am child process,pid id %d.I am exiting.\n",getpid());exit(0);}else if(pid > 0){ // 父進程sleep(2); // 保證子進程先運行printf("I am father, i am exited\n\n");system("ps -ef | grep defunct"); // 查看有沒有僵尸進程}return 0; }

測試結果:

  • 還有一些技巧,就是 fork() 兩次,父進程 fork() 一個子進程,然后繼續工作,子進程 fork() 一 個孫進程后退出,那么孫進程被 init 接管,孫進程結束后,init (1 號進程)會回收。不過子進程的回收還要自己做。《UNIX環境高級編程》8.6節說的非常詳細。原理是將子進程成為孤兒進程,從而其的父進程變為 init 進程(1 號進程),通過 init 進程(1 號進程)可以處理僵尸進程。

測試代碼:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h>int main() {pid_t pid;//創建第一個子進程pid = fork();if (pid < 0){ // 出錯perror("fork error:");exit(1);}else if (pid == 0){//子進程//子進程再創建子進程printf("I am the first child process.pid:%d\tppid:%d\n",getpid(),getppid());pid = fork();if (pid < 0){perror("fork error:");exit(1);}else if(pid == 0){ // 子進程//睡眠3s保證下面的父進程退出,這樣當前子進程的父親就是 init 進程sleep(3);printf("I am the second child process.pid: %d\tppid:%d\n",getpid(),getppid());exit(0);}else if (pid >0){ //父進程退出printf("first procee is exited.\n");exit(0);}}else if(pid > 0){ // 父進程// 父進程處理第一個子進程退出,回收其資源if (waitpid(pid, NULL, 0) != pid){perror("waitepid error:");exit(1);}exit(0);}return 0; }

測試結果:

04. 附錄

4.1 參考博客:【Linux系統編程】特殊進程之僵尸進程

4.2 參考網址:百度百科

總結

以上是生活随笔為你收集整理的【Linux系统编程】特殊进程之僵尸进程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。