目錄
一,僵尸進(jìn)程
1,僵尸進(jìn)程
2,僵尸進(jìn)程的危害
二,孤兒進(jìn)程
1,孤兒進(jìn)程
三,進(jìn)程等待
1,進(jìn)程等待的必要性
2,wait 方法
3,waitpid 方法
4,回收小結(jié)
一,僵尸進(jìn)程
1,僵尸進(jìn)程
僵死狀態(tài)(Zombies)是一個(gè)比較特殊的狀態(tài)。
當(dāng)進(jìn)程退出并且父進(jìn)程(使用wait()系統(tǒng)調(diào)用,后面講) 沒(méi)有讀取到子進(jìn)程退出的返回代碼時(shí)就會(huì)產(chǎn)生僵死(尸)進(jìn)程 僵死進(jìn)程會(huì)以終止?fàn)顟B(tài)保持在進(jìn)程表中,并且會(huì)一直在等待父進(jìn)程讀取退出狀態(tài)代碼。
所以,只要子進(jìn)程退出,父進(jìn)程還在運(yùn)行,但父進(jìn)程沒(méi)有讀取子進(jìn)程狀態(tài),子進(jìn)程進(jìn)入Z狀態(tài)
來(lái)一個(gè)創(chuàng)建維持30秒的僵死進(jìn)程例子:
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t id = fork();
if (id < 0) {
perror("fork");
return 1;
}
else if (id > 0) { //parent
printf("parent[%d] is sleeping...\n", getpid());
sleep(30);
}
else {
printf("child[%d] is begin Z...\n", getpid());
sleep(5);
exit(EXIT_SUCCESS);
}
return 0;
}
當(dāng)fork()函數(shù)返回值,父進(jìn)程和子進(jìn)程同時(shí)啟動(dòng),當(dāng)子進(jìn)程運(yùn)行結(jié)束退出進(jìn)程時(shí),父進(jìn)程還在等待,此時(shí)子進(jìn)程一直在等待父進(jìn)程讀取其退出狀態(tài)代碼,于是產(chǎn)生了僵尸狀態(tài);
僵尸狀體會(huì)造成內(nèi)存泄漏,我們要盡可能避免;
2,僵尸進(jìn)程的危害
進(jìn)程的退出狀態(tài)必須被維持下去,因?yàn)樗嬖V關(guān)心它的進(jìn)程(父進(jìn)程),你交給我的任務(wù),我辦的怎么樣了。可父進(jìn)程如果一直不讀取,那子進(jìn)程就一直處于Z狀態(tài)?是的!
維護(hù)退出狀態(tài)本身就是要用數(shù)據(jù)維護(hù),也屬于進(jìn)程基本信息,所以保存在task_struct(PCB)中,換句話說(shuō),Z狀態(tài)一直不退出,PCB一直都要維護(hù)?是的!
那一個(gè)父進(jìn)程創(chuàng)建了很多子進(jìn)程,就是不回收,是不是就會(huì)造成內(nèi)存資源的浪費(fèi)?是的!因?yàn)閿?shù)據(jù)結(jié)構(gòu)對(duì)象本身就要占用內(nèi)存,想想C中定義一個(gè)結(jié)構(gòu)體變量(對(duì)象),是要在內(nèi)存的某個(gè)位置進(jìn)行開(kāi)辟空間!
內(nèi)存泄漏?是的!
二,孤兒進(jìn)程
1,孤兒進(jìn)程
父進(jìn)程如果提前退出,那么子進(jìn)程后退出,進(jìn)入Z之后,那該如何處理呢?
父進(jìn)程先退出,子進(jìn)程就稱之為“孤兒進(jìn)程”
孤兒進(jìn)程被1號(hào)init進(jìn)程領(lǐng)養(yǎng),當(dāng)然要有init進(jìn)程回收嘍。
我們寫(xiě)一個(gè)進(jìn)程來(lái)感受一下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t id = fork();
if (id < 0) {
perror("fork");
return 1;
}
else if (id == 0) {//child
printf("I am child, pid : %d\n", getpid());
sleep(10);
}
else {//parent
printf("I am parent, pid: %d\n", getpid());
sleep(3);
exit(0);
}
return 0;
}
fork()函數(shù)返回后,子進(jìn)程和父進(jìn)程同時(shí)運(yùn)行,當(dāng)父進(jìn)程執(zhí)行結(jié)束并且退出后,子進(jìn)程還在運(yùn)行,此時(shí)子進(jìn)程淪為孤兒!
一般孤兒進(jìn)程最后會(huì)被1號(hào)init進(jìn)程領(lǐng)養(yǎng),不會(huì)造成內(nèi)存泄漏;
三,進(jìn)程等待
1,進(jìn)程等待的必要性
之前講過(guò),子進(jìn)程退出,父進(jìn)程如果不管不顧,就可能造成‘僵尸進(jìn)程’的問(wèn)題,進(jìn)而造成內(nèi)存泄漏。
另外,進(jìn)程一旦變成僵尸狀態(tài),那就刀槍不入,“殺人不眨眼”的kill -9 也無(wú)能為力,因?yàn)檎l(shuí)也沒(méi)有辦法殺死一個(gè)已經(jīng)死去的進(jìn)程。
最后,父進(jìn)程派給子進(jìn)程的任務(wù)完成的如何,我們需要知道。如子進(jìn)程運(yùn)行完成,結(jié)果對(duì)還是不對(duì), 或者是否正常退出。
父進(jìn)程通過(guò)進(jìn)程等待的方式,回收子進(jìn)程資源,獲取子進(jìn)程退出信息
2,wait 方法
pid_t wait(int*status);
返回值: 成功返回被等待進(jìn)程pid,失敗返回-1。
參數(shù): 輸出型參數(shù),獲取子進(jìn)程退出狀態(tài),不關(guān)心則可以設(shè)置成為NULL
#include <stdio. h>
#include <unistd.h>
#include <stdlib.h>
#include<sys/types.h>
#include<sys / wait.h>
int main()
{
pid_t id = fork();
if (id < 0) {
perror("fork");
return 1;
}
else if (id == 0) {
//parent
printf("child[%d] is sleeping...\n", getpid());
sleep(5);
exit(3);
}
int status = 0;
pid_t rid = wait(&status);
if (rid > 0)
{
printf("parent[%d] is begin Z...\n", rid);
sleep(10);
}
else
{
printf("進(jìn)程失敗:rid:%d\n", rid);
}
return 0;
}
這樣子 wait 會(huì)自動(dòng)及時(shí)回收子進(jìn)程,不會(huì)形成僵尸,不會(huì)造成內(nèi)存泄漏;
3,waitpid 方法
pid_ t waitpid(pid_t pid, int *status, int options);
返回值: 當(dāng)正常返回的時(shí)候waitpid返回收集到的子進(jìn)程的進(jìn)程ID;
如果設(shè)置了選項(xiàng)WNOHANG,而調(diào)用中waitpid發(fā)現(xiàn)沒(méi)有已退出的子進(jìn)程可收集,則返回0;
如果調(diào)用中出錯(cuò),則返回-1,這時(shí)errno會(huì)被設(shè)置成相應(yīng)的值以指示錯(cuò)誤所在;
參數(shù):
pid: Pid=-1,等待任一個(gè)子進(jìn)程。與wait等效。 Pid>0.等待其進(jìn)程ID與pid相等的子進(jìn)程。 status: WIFEXITED(status):
若為正常終止子進(jìn)程返回的狀態(tài),則為真。
(查看進(jìn)程是否是正常退出) WEXITSTATUS(status): 若WIFEXITED非零,提取子進(jìn)程退出碼。(查看進(jìn)程的退出碼) options: WNOHANG:
若pid指定的子進(jìn)程沒(méi)有結(jié)束,則waitpid()函數(shù)返回0,不予以等待。若正常結(jié)束,則返回該子進(jìn) 程的ID。
#include <stdio. h>
#include <unistd.h>
#include <stdlib.h>
#include<sys/types.h>
#include<sys / wait.h>
int main()
{
pid_t id = fork();
if (id < 0) {
perror("fork");
return 1;
}
else if (id == 0) {
//parent
printf("child[%d] is sleeping...\n", getpid());
sleep(5);
exit(3);
}
int status = 0;
pid_ t rid = waitpid(-1,&status,0);
if (rid > 0)
{
printf("parent[%d] is begin Z...\n", rid);
sleep(10);
}
else
{
printf("進(jìn)程失敗:rid:%d\n", rid);
}
return 0;
}
4,回收小結(jié)
如果子進(jìn)程已經(jīng)退出,調(diào)用wait/waitpid時(shí),wait/waitpid 會(huì)立即返回,并且釋放資源,獲得子進(jìn)程退出信息。
如果在任意時(shí)刻調(diào)用 wait/waitpid,子進(jìn)程存在且正常運(yùn)行,則進(jìn)程可能阻塞。
如果不存在該子進(jìn)程,則立即出錯(cuò)返回。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-761074.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-761074.html
到了這里,關(guān)于【Linux】僵尸與孤兒 && 進(jìn)程等待的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!