孤兒進程與僵尸進程

孤兒進程:父進程先于子進程結束(遇到return、exit、異常終止等情況時),則子進程成為孤兒進程,子進程的父進程成為init進程,稱為init進程領養孤兒進程。可以通過getppid函數來查看孤兒進程的父進程ID,即init進程的ID,init進程的ID具體是多少取決于操作系統對進程的調度,其值是不確定的。在操作系統中,init進程也不止一個,可通過ps aux詳細查看。

僵尸進程:進程終止,父進程尚未回收,子進程殘留資源(PCB)存放于內核中,變成僵尸(Zombie)進程。

特別注意,僵尸進程是不能使用kill命令清除掉的。因為kill命令只是用來終止進程的,而僵尸進程已經終止。

// orphan.c? //shell產生子進程執行該程序

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>int main(void)
{	pid_t pid;pid = fork();  //創建子進程if (pid == 0) {while (1) {printf("I am child, my parent pid = %d\n", getppid());sleep(1);  //子進程一直運行}} else if (pid > 0) {printf("I am parent, my pid is = %d\n", getpid());sleep(9);printf("------------parent going to die------------\n");  //父進程先于子進程結束,子進程變為孤兒進程} else {perror("fork");return 1; //等價于exit(1),都是結束進程,且進程結束狀態置1表示出錯}return 0;
}

[root@localhost wait]# ./orphan

I am parent, my pid is = 26900

I am child, my parent pid = 26900

I am child, my parent pid = 26900

I am child, my parent pid = 26900

I am child, my parent pid = 26900

I am child, my parent pid = 26900

I am child, my parent pid = 26900

I am child, my parent pid = 26900

I am child, my parent pid = 26900

I am child, my parent pid = 26900

------------parent going to die------------ //父進程正常結束

I am child, my parent pid = 1? //子進程為孤兒進程,被init進程領養,即其父進程為init進程

[root@localhost wait]# I am child, my parent pid = 1 //父進程結束,shell進程收回前臺,等待命令交互

I am child, my parent pid = 1 //子進程一直執行,為孤兒進程

I am child, my parent pid = 1

I am child, my parent pid = 1

I am child, my parent pid = 1

I am child, my parent pid = 1

//zoom.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>int main(void)
{pid_t pid;pid = fork(); if (pid == 0) {printf("---child, my parent= %d, going to sleep 10s\n", getppid());sleep(10);printf("-------------child die--------------\n"); //子進程先正常結束} else if (pid > 0) {while (1) {printf("I am parent, pid = %d, myson = %d\n", getpid(), pid);sleep(1);}    //父進程一直運行} else {perror("fork");return 1;}return 0;
}

[root@localhost wait]# ./zoom

I am parent, pid = 27152, myson = 27153

---child, my parent= 27152, going to sleep 10s

I am parent, pid = 27152, myson = 27153

I am parent, pid = 27152, myson = 27153

I am parent, pid = 27152, myson = 27153

I am parent, pid = 27152, myson = 27153

I am parent, pid = 27152, myson = 27153

I am parent, pid = 27152, myson = 27153

I am parent, pid = 27152, myson = 27153

I am parent, pid = 27152, myson = 27153

I am parent, pid = 27152, myson = 27153

I am parent, pid = 27152, myson = 27153

-------------child die--------------? //子進程死亡

I am parent, pid = 27152, myson = 27153 //父進程一直運行,一直占據前臺,shell進程無法獲得前臺交互 ?且子進程結束后,父進程沒有對子進程殘留在內核中的PCB進行回收,從而子進程變為僵尸進程。

I am parent, pid = 27152, myson = 27153

I am parent, pid = 27152, myson = 27153

I am parent, pid = 27152, myson = 27153

[root@localhost wait] # ps aux

root???? 27152? 0.0? 0.0?? 4160?? 352 pts/1??? S+?? 03:11 ??0:00 ./zoom

root???? 27153? 0.0? 0.0????? 0???? 0 pts/1??? Z+?? 03:11?? 0:00 [zoom] <defunct>

root????? 27155? 0.0? 0.0????? 0???? 0 ???????? R??? 03:12?? 0:00 [kworker/3:0]

root????? 27163? 0.0? 0.0 107892?? 360 ???????? S??? 03:12?? 0:00 sleep 60

root ?????27164? 0.0? 0.0 123360? 1384 pts/0??? R+?? 03:12?? 0:00 ps aux

[root@localhost wait]# kill 27152?

由上可以看出,父進程27152,為S+,表示該進程在后臺運行(注意,ps aux命令是在另一個終端執行的,因此相對于另一個shell終端,父進程在后臺運行);子進程27153,為Z+,表示僵尸進程,說明該進程終止后,其殘留在內核的PCB資源沒有被父進程回收;而ps aux這個命令的進程為R+,表示在前臺運行,即就在pts/0設備終端的前臺運行。而前兩個進程屬于pts/1設備。[zoom] <defunct>? defunct表示已故的,不復存在的,但其痕跡仍然殘留在內核中,占用內存資源,因此需要做到及時對僵尸進程回收和清除。

總結:在每個進程退出的時候,?內核釋放該進程所有的資源,包括打開的文件,占用的內存等。但是仍然為其保留一定的信息(包括進程號the process ID,退出狀態the termination status of the process,運行時間the amount of CPU time taken by the process等)。直到父進程通過wait / waitpid來取時才釋放。 另外,如果父進程一直不結束(不終止),在不調用wait或waitpid的情況下,其子進程結束后會變為僵尸進程,殘留在內核中,此時若父進程結束了,那么這些僵尸進程因為沒有了父進程,就會變為孤兒進程被init進程領養,init進程就會對這些僵尸進程進行回收,然后清除。因此,父進程結束了,其子進程會被回收。孤兒進程結束后,也會被init進程回收。如果要回收一個進程,除了通過其父進程調用wait或waitpid函數外,還可以殺死其父進程,讓其變為孤兒進程,被init進程回收。

系統所能使用的進程號是有限的,如果大量的產生僵死進程,將因為沒有可用的進程號而導致系統不能產生新的進程. 此即為僵尸進程的危害,應當避免。可以fork兩次,?父進程fork一個子進程,然后繼續工作,子進程fork一個孫進程后退出,那么孫進程被init接管,孫進程結束后,init會回收。不過子進程的回收還要自己做。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385360.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385360.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385360.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

1043. 輸出PATest(20)

給定一個長度不超過10000的、僅由英文字母構成的字符串。請將字符重新調整順序&#xff0c;按“PATestPATest....”這樣的順序輸出&#xff0c;并忽略其它字符。當然&#xff0c;六種字符的個數不一定是一樣多的&#xff0c;若某種字符已經輸出完&#xff0c;則余下的字符仍按P…

wait函數

#include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); 僵尸進程。進程結束后放棄了幾乎所有的內存空間&#xff0c;沒有任何可以執行的代碼&#xff0c;也不能被調度&#xff0c;僅僅在進程列表中保留著一個位置&#xff0c;記載著該進程的退出…

map與unordered_map

時間復雜度&#xff1a; mapunordered_mapOrderingincreasing orderno orderImplementationSelf balancing BSTHash Tablesearch timelog(n) O(1&#xff09;: 平均水ping O(n&#xff09;&#xff1a;最糟糕情況 Insertion timelog(n) RebalanceSame sa searchDelete timelo…

waitpid函數

#include <sys/wait.h> #include <sys/types.h> pid_t waitpid(pid_t pid, int *status, int options); 作用&#xff1a;同wait&#xff0c;但可指定pid進程清理&#xff0c;可以不阻塞。 waitpid函數的第二個參數int *status跟wait函數的形參一樣&#xff0c;…

進程間通信的方法

Linux環境下&#xff0c;進程地址空間相互獨立&#xff0c;每個進程各自有不同的用戶地址空間。任何一個進程的全局變量在另一個進程中都看不到&#xff0c;所以進程和進程之間不能相互訪問&#xff0c;要交換數據必須通過內核&#xff0c;在內核中開辟一塊緩沖區&#xff0c;進…

管道的概念(匿名管道)

管道是一種最基本的IPC機制&#xff0c;作用于有血緣關系的進程之間&#xff0c;完成數據傳遞。調用pipe系統函數即可創建一個管道。管道有如下特質&#xff1a;1.其本質是一個偽文件&#xff08;實為內核緩沖區&#xff09;&#xff0c;偽文件即不是真正的文件&#xff0c;不占…

1023. 組個最小數 (20)

給定數字0-9各若干個。你可以以任意順序排列這些數字&#xff0c;但必須全部使用。目標是使得最后得到的數盡可能小&#xff08;注意0不能做首位&#xff09;。例如&#xff1a;給定兩個0&#xff0c;兩個1&#xff0c;三個5&#xff0c;一個8&#xff0c;我們得到的最小的數就…

pipe函數

#include <unistd.h> int pipe(int pipefd[2]); 作用&#xff1a;創建管道 成功&#xff1a;0&#xff1b;失敗&#xff1a;-1&#xff0c;設置errno 函數調用成功返回r/w兩個文件描述符。無需open&#xff0c;但需手動close。規定&#xff1a;fd[0] …

二分查找總結

二分查找法作為一種常見的查找方法&#xff0c;將原本是線性時間提升到了對數時間范圍&#xff0c;大大縮短了搜索時間&#xff0c;具有很大的應用場景&#xff0c;而在LeetCode中&#xff0c;要運用二分搜索法來解的題目也有很多&#xff0c;但是實際上二分查找法的查找目標有…

管道的讀寫行為

使用管道需要注意以下4種特殊情況&#xff08;默認都是阻塞I/O操作&#xff0c;沒有設置O_NONBLOCK標志&#xff09;&#xff1a; 1. 如果所有指向管道寫端的文件描述符都關閉了&#xff08;管道寫端引用計數為0&#xff09;&#xff0c;而仍然有進程從管道的讀端讀數據&#…

【C++ Primer | 08】課后習題答案

文章目錄練習8.13練習8.13 include <iostream> #include <sstream> #include <fstream> #include <string> #include <vector> using namespace std;struct PersonInfo {string name;vector<string> phones; };bool valid(const string&…

管道緩沖區大小

可以使用ulimit –a 命令來查看當前系統中創建管道文件所對應的內核緩沖區大小。通常為&#xff1a;pipe size 4K&#xff0c;即一個頁面大小。也可以使用fpathconf函數來查看&#xff1a; #include <unistd.h> long fpathconf(int fd, int name); 當需要查看管道的大…

FIFO(命名管道)

FIFO常被稱為命名管道&#xff0c;以區分管道(pipe)。管道(pipe)只能用于“有血緣關系”的進程間。但通過FIFO&#xff0c;不相關的進程也能交換數據。FIFO是Linux基礎文件類型中的一種&#xff08;p,管道文件&#xff09;。但FIFO文件在磁盤上沒有數據塊&#xff0c;僅僅用來標…

文件進程間通信

使用文件也可以完成IPC&#xff0c;理論依據是&#xff0c;fork后&#xff0c;父子進程共享文件描述符。也就共享打開的文件。 //父子進程共享打開的文件。借助文件進行進程間通信&#xff08;可先打開文件&#xff0c;再創建子進程&#xff09; #include <unistd.h> #…

mmap內存映射、system V共享內存和Posix共享內存

linux內核支持多種共享內存方式&#xff0c;如mmap內存映射&#xff0c;Posix共享內存&#xff0c;以system V共享內存。當內核空間和用戶空間存在大量數據交互時&#xff0c;共享內存映射就成了這種情況下的不二選擇。它能夠最大限度的降低內核空間和用戶空間之間的數據拷貝&a…

mmap、munmap函數

#include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset); int munmap(void *addr, size_t length); void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset); 返回&#xff1a;成功&…

mmap和munmap對文件進行操作(讀寫等)

//mmap、munmap函數的使用 #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <sys/mman.h>void sys_err(char *str) {perror(str);exit(1); }…

1017. A除以B (20)

本題要求計算A/B&#xff0c;其中A是不超過1000位的正整數&#xff0c;B是1位正整數。你需要輸出商數Q和余數R&#xff0c;使得A B * Q R成立。 輸入格式&#xff1a; 輸入在1行中依次給出A和B&#xff0c;中間以1空格分隔。 輸出格式&#xff1a; 在1行中依次輸出Q和R&#…

mmap父子進程間通信

父子等有血緣關系的進程之間也可以通過mmap建立的映射區來完成數據通信。但相應的要在創建映射區的時候指定對應的標志位參數flags&#xff1a;MAP_PRIVATE&#xff1a;&#xff08;私有映射&#xff09;父子進程各自獨占映射區&#xff1b;MAP_SHARED&#xff1a;&#xff08;…

匿名映射

通過使用我們發現&#xff0c;使用映射區來完成文件讀寫操作十分方便&#xff0c;父子進程間通信也較容易。但缺陷是&#xff0c;每次創建映射區一定要依賴一個文件才能實現。通常為了建立映射區要open一個temp文件&#xff0c;創建好了再unlink、close掉&#xff0c;比較麻煩。…