Linux / 僵尸进程、孤儿进程 产生原因、有什么危害、如何预防(解决方案)
一、產生原因
1、僵尸進程
子進程退出,父進程運行,父進程沒有調用 wait 或者 waitpid 函數,那么子進程就處于僵尸狀態(Z)。
2、孤兒進程
子進程運行,父進程退出,孤兒進程由?init 進程收養,此時子進程就變成了孤兒進程。
3、系統為什么需要僵尸進程這種進程狀態
由于父進程創建子進程是異步的,雙方不知道各自的運行狀態,而父進程有的時候需要知道子進程退出時的一些信息,所以 linux 提供了一種機制,通過讓子進程退出時向父進程發送 SIGCHRD 信號來告知父進程,子進程已經退出了。同時,父進程通過調用 wait 和 waitpid 來獲取子進程的退出信息。
二、有什么危害
1、僵尸進程
有很大危害。因為僵尸進程已經挺尸了,對系統沒有什么作用,但是依然在進程表占了位置,如果 os 有大量的僵尸進程,那么進程號就會被大量無故占用,嚴重的話再次 fork 進程可能失敗。
2、孤兒進程
沒什么危害。因為該進程只是父進程換成了 init ,依然可以正常運行。
三、如何預防(解決方案)
1、kill 父進程
kill 父進程之后,僵尸進程會變成孤兒僵尸進程,由?init 收養,通過 init 是循環 wait ,從而讓子進程徹底退出。
2、注冊 SIGCHRD 信號的信號處理函數,在函數中調用 wait(調用者堵塞) 或者 waitpid(可以配置調用者不堵塞) 。
3、fork 兩次,創建子進程,子進程在創建孫進程,最后 kill 子進程,那么孫進程就由 init 收養。
栗子:
#include <iostream> #include <signal.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.h>void signalproc(int isig) {int istatus;waitpid(SIG_BLOCK, &istatus, WNOHANG); }int main() {signal(SIGCHLD, signalproc);pid_t pid;int r = fork();if (r < 0)std::cout << "創建進程失敗!" << std::endl;else if (r == 0){std::cout << "子進程開始運行!" << std::endl;int r1 = fork();if (r < 0)std::cout << "創建孫進程失敗!" << std::endl;else if (r1 == 0){std::cout << "孫進程開始運行,并進入循環!" << std::endl;while (true){std::cout << "Sun" << std::endl;sleep(1);}}std::cout << "子進程退出" << std::endl;exit(0);}std::cout << "父進程開始進入循環!" << std::endl;while (true){std::cout << "parent" << std::endl;sleep(1);}return 0; }結果:
父進程開始進入循環! parent 子進程開始運行! 子進程退出 孫進程開始運行,并進入循環! Sun parent Sun parent Sun parent Sun parent輸入指令:
ps -eo pid,ppid,sid,comm,stat | grep -E 'bash|fork'?結果:
13997 2539 13997 bash Ss 15816 2539 15816 bash Ss 15939 15816 15816 forktest S+ 15941 1210 15816 forktest S+注意:
由于我的系統是 ubuntu 18.04,所以 forktest 的孫進程的父進程是 1210,不是 init 。1210 進程是 systemd 進程,該進程的具體含義后續有時間會說明
?
?
(SAW:Game Over!)
總結
以上是生活随笔為你收集整理的Linux / 僵尸进程、孤儿进程 产生原因、有什么危害、如何预防(解决方案)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux / offsetof 和 c
- 下一篇: Linux / 守护进程