Linux 僵尸进程可以被杀死吗?
在 Unix 進(jìn)程模型中,父進(jìn)程和其所產(chǎn)生的子進(jìn)程是異步運(yùn)行的,所以如果子進(jìn)程在結(jié)束后,會(huì)留下一些信息需要父進(jìn)程使用 ?wait ?/ ?waitpid ?來接收。而如果父進(jìn)程太忙了,沒有調(diào)用 ?wait ?/ ?waitpid ?的話,子進(jìn)程就會(huì)變成僵尸進(jìn)程。
僵尸進(jìn)程不可能被殺死,因?yàn)樗呀?jīng)死了,不存在再死一次的問題。死的對(duì)立面是活,死者已死。只有活的進(jìn)程才可能被殺死。
什么是僵尸進(jìn)程?
首先要明確一點(diǎn),僵尸進(jìn)程的含義是:子進(jìn)程已經(jīng)死了,但是父進(jìn)程還沒有wait它的一個(gè)中間狀態(tài),這個(gè)時(shí)候子進(jìn)程是一個(gè)僵尸。正常情況下子死,父wait,清理掉子進(jìn)程的task_struct,釋放子進(jìn)程的PID:
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h>int main(void) {pid_t pid,wait_pid;int status;pid = fork();if(pid == 1){perror("Cannot create new process\n");exit(1);}else if(pid == 0){printf("child process id:%ld\n",(long)getpid());pause();_exit(0);}else{#if 0printf("ppid :%d\n",getpid());while(1);#endifdo{wait_pid = waitpid(pid,&status,WUNTRACED | WCONTINUED);if(WIFEXITED(status))printf("child process is killed by signal %d\n",WIFSIGNALED(status));}while(!WIFEXITED(status) && !WIFSIGNALED(status));exit(0);} }執(zhí)行
gcc ps_wait.c -pthread && ./a.out執(zhí)行情況如下
linux@ubuntu:~/linux$ gcc ps_wait.c -pthread && ./a.out child process id:4578每次執(zhí)行生成的子進(jìn)程會(huì)不同,這里只是舉例子說明
運(yùn)行,我們看到2個(gè)a.out進(jìn)程
殺死子進(jìn)程4578,看到父進(jìn)程的打印:
之后,4578會(huì)消失,因?yàn)楦高M(jìn)程執(zhí)行到了wait,也知道了子進(jìn)程是被信號(hào)2殺掉的。但是如果子進(jìn)程死了,父進(jìn)程不執(zhí)行到wait,比如把上圖中的"#if 0"改為"#if 1",殺死子進(jìn)程后,子進(jìn)程就會(huì)是一個(gè)僵尸:
注意,這里說的是子進(jìn)程會(huì)變成一個(gè)僵尸進(jìn)程
代碼如下:
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h>int main(void) {pid_t pid,wait_pid;int status;pid = fork();if(pid == 1){perror("Cannot create new process\n");exit(1);}else if(pid == 0){printf("child process id:%ld\n",(long)getpid());pause();_exit(0);}else{#if 1printf("ppid :%d\n",getpid());while(1);#endifdo{wait_pid = waitpid(pid,&status,WUNTRACED | WCONTINUED);if(WIFEXITED(status))printf("child process is killed by signal %d\n",WIFSIGNALED(status));}while(!WIFEXITED(status) && !WIFSIGNALED(status));exit(0);} }我們重新運(yùn)行,當(dāng)我們用kill -2殺掉子進(jìn)程4628后,我們發(fā)現(xiàn)4628成為一個(gè)僵尸,狀態(tài)變?yōu)閆+,名字上也加了一個(gè)棺材[],成為[a.out]
Z表示的是僵尸進(jìn)程,[]符號(hào)就像一口棺材一樣,把這個(gè)僵尸進(jìn)程給裝了起來
僵尸不可能被殺死?
我們看到上面4628是個(gè)僵尸很不爽,所以我們想把它干掉,據(jù)說Linux有個(gè)信號(hào)9,神擋殺神,佛擋殺佛,我們現(xiàn)在來用kill -9干掉4628
從上圖可以看出,我們把4628用kill -9捅了好多刀,但是最后看4628這個(gè)僵尸,還是沒有消失。
因?yàn)榻┦呀?jīng)是死了,它不可能再次被殺死,你給它捅一萬刀,它也是個(gè)死人,不可能再次死!
僵尸不可能被殺死,因?yàn)樗呀?jīng)死了!
兩種方法來清理僵尸進(jìn)程1、只等父進(jìn)程來wait清理尸體了。2、這個(gè)時(shí)候我們能夠把僵尸消失掉的方法,就是殺死僵尸進(jìn)程的父進(jìn)程4627。
一個(gè)僵尸可以被殺死的假象
下面的這個(gè)程序證明「僵尸可以被殺死」這樣的假象。
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h>static void *thread_fun(void *param) {while(1); }int main(void) {pthread_t tid;int ret;ret = pthread_create(&tid,NULL,thread_fun,NULL);if(ret == -1){perror("cannot create new thread\n");return -1;}pthread_exit(0);return 0; }我們?cè)谥骶€程里面,pthread_create()創(chuàng)建線程后,pthread_exit()退出,這個(gè)時(shí)候我們會(huì)發(fā)現(xiàn),在ps命令里面,a.out顯示為一個(gè)僵尸進(jìn)程。這個(gè)僵尸進(jìn)程出現(xiàn)是我們?cè)趖hread_fun 里面寫了一個(gè)while(1)不能退出導(dǎo)致的。
繼續(xù),開始我們的表演,我們使用下面的命令來殺死這個(gè)僵尸進(jìn)程。
kill -9 4730
我們會(huì)驚奇地發(fā)現(xiàn),4730真地會(huì)從ps命令里面消失。
在沒有執(zhí)行命令殺死 4730 之前,我們「猜測(cè)」能殺死僵尸的本質(zhì)原因是,當(dāng)主線程4730調(diào)用pthread_exit()退出后,主線程4730的狀態(tài)確實(shí)是僵尸了,但是該進(jìn)程里面的4731線程,卻沒有死。
我們看看proc 文件系統(tǒng)下面的進(jìn)程狀態(tài)
看看4731:
4731是活著的,證明整個(gè)進(jìn)程并沒有掛。所以4730的退出,只是讓整個(gè)進(jìn)程半死。而由于ps這些命令的誤會(huì),4730湊巧又是整個(gè)進(jìn)程的PID,它顯示地好像整個(gè)4370成了僵尸一樣。
4731這個(gè)子進(jìn)程什么時(shí)候死了呢?那么,根據(jù)POSIX標(biāo)準(zhǔn)關(guān)于信號(hào)(signal)的定義,當(dāng)我們執(zhí)行kill -9 4730 (4730是4730和4731的TGID,也是整個(gè)進(jìn)程用戶態(tài)視角的PID)的時(shí)候,是要?dú)⑺勒麄€(gè)4730進(jìn)程的,所以這個(gè)時(shí)候4731被我們殺死,整個(gè)進(jìn)程就都死了,這個(gè)時(shí)候,執(zhí)行到父進(jìn)程的wait邏輯,導(dǎo)致僵尸消失。
所以,在本例中,kill -9 4730看起來是"殺死了僵尸”,實(shí)際是殺死了4730整個(gè)進(jìn)程(里面的每個(gè)線程),導(dǎo)致整個(gè)進(jìn)程死。在此之前,整個(gè)進(jìn)程實(shí)際還是活的。
掃碼或長(zhǎng)按關(guān)注
回復(fù)「籃球的大肚子」進(jìn)入技術(shù)群聊
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)
總結(jié)
以上是生活随笔為你收集整理的Linux 僵尸进程可以被杀死吗?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python验证码登录代码_Python
- 下一篇: 搭建Hadoop环境(超详细)