? 孤兒行程的概念:
若子行程的父行程已經死掉,而子行程還存活著,這個行程就成了孤兒行程,
? 為了保證每個行程都有一個父行程,孤兒行程會被init行程領養,init行程成為了孤兒行程的養父行程,當孤兒行程退出之后,由init行程完成對孤兒行程的回收,
? 模擬孤兒行程的案例
撰寫模擬孤兒行程的代碼講解孤兒行程,驗證孤兒行程的父行程是否由原來的父行程變成了init行程,
孤兒行程: 父行程先退出, 子行程就變成了孤兒行程, 此時被init行程領養,
當孤兒行程退出之后, 就會被init行程回收.
//模擬孤兒行程 函式測驗
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
//創建子行程
//pid_t fork(void);
pid_t pid = fork();
if(pid<0)
{
perror("fork error");
return -1;
}
else if(pid>0)//父行程
{
/*
man getpid for help
*/
sleep(5);
printf("father: pid==[%d] fpid==[%d]\n",getpid(),getppid());
}
else if(pid == 0)//子行程
{
printf("child: pid==[%d] fpid==[%d]\n",getpid(),getppid());
sleep(10);
printf("child: pid==[%d] fpid==[%d]\n",getpid(),getppid());
}
return 0;
}
$ gcc -g -Wall orphan.c -o orphan
$ ./orphan
child: pid==[95035] fpid==[95034]
father: pid==[95034] fpid==[91160]
child: pid==[95035] fpid==[1] //被init行程回收
僵尸行程的概念:
若子行程死了,父行程還活著, 但是父行程沒有呼叫wait或waitpid函式完成對子行程的回收,則該子行程就成了僵尸行程,
? 如何解決僵尸行程
? 由于僵尸行程是一個已經死亡的行程,所以不能使用kill命令將其殺死
? 通過殺死其父行程的方法可以消除僵尸行程,
殺死其父行程后,這個僵尸行程會被init行程領養,由init行程完成對僵尸行程的回收,
? 模擬僵尸行程的案例
撰寫模擬僵尸行程的代碼講解僵尸行程, 驗證若子行程先于父行程退出, 而父行程沒有呼叫wait或者waitpid函式進行回收, 從而使子行程成為了僵尸行程.
//模擬僵尸行程 函式測驗
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
//創建子行程
//pid_t fork(void);
pid_t pid = fork();
if(pid<0)
{
perror("fork error");
return -1;
}
else if(pid>0)//父行程
{
/*
man getpid for help
*/
sleep(20);//sleep 讓子行程先結束
printf("father: pid==[%d] fpid==[%d]\n",getpid(),getppid());
}
else if(pid == 0)//子行程
{
printf("child: pid==[%d] fpid==[%d]\n",getpid(),getppid());
}
return 0;
}
$ ps -ef | grep zombie
wym 95932 95707 0 23:29 pts/6 00:00:00 grep --color=auto zombie
$ ps -ef | grep zombie
wym 96155 91160 0 23:29 pts/5 00:00:00 ./zombie
wym 96156 96155 0 23:29 pts/5 00:00:00 [zombie] <defunct>
#defunct 表明是僵尸行程,無法接受信號,kill -9 也無法殺死
#如何解決僵尸行程:
應該使用殺死僵尸行程父行程的方法來解決僵尸行程
解決僵尸行程的更好方法是使用行程回收函式
行程回收函式
? wait函式
? 函式原型:
pid_t wait(int *status);
? 函式作用:
? 阻塞并等待子行程退出
? 回收子行程殘留資源
? 獲取子行程結束狀態(退出原因),
? 回傳值:
? 成功:清理掉的子行程ID;
? 失敗:-1 (沒有子行程)
? status引數:子行程的退出狀態 – 傳出引數
? WIFEXITED(status):為非0 → 行程正常結束
WEXITSTATUS(status):獲取行程退出狀態
? WIFSIGNALED(status):為非0 → 行程例外終止
WTERMSIG(status):取得行程終止的信號編號,
? wait函式練習
使用wait函式完成父行程對子行程的回收
//父行程呼叫wait完成對子行程地回收 函式測驗
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>/*for wait*/
#include <unistd.h>
int main()
{
//創建子行程
//pid_t fork(void);
pid_t pid = fork();
if(pid<0)
{
perror("fork error");
return -1;
}
else if(pid>0)//父行程
{
printf("father: pid==[%d] fpid==[%d]\n",getpid(),getppid());
int status = 0;
pid_t wpid = wait(&status);
printf("wpid==[%d]\n",wpid);
if(WIFEXITED(status))//正常退出
{
printf("child normal exit,status==[%d]\n",WEXITSTATUS(status));
}else if(WIFSIGNALED(status))//被信號殺死
{
printf("child killed by signal,status==[%d]\n",WTERMSIG(status));
}
}
else if(pid == 0)//子行程
{
printf("child: pid==[%d] fpid==[%d]\n",getpid(),getppid());
sleep(20);
/*
sleep 20 可以測驗被信號 15(Terminated) 殺死
$ ps -ef | grep wait
wym 111409 91160 0 00:04 pts/5 00:00:00 ./wait
wym 111410 111409 0 00:04 pts/5 00:00:00 ./wait
wym 111436 95707 0 00:04 pts/6 00:00:00 grep --color=auto wait
$ kill -15 111409
$ ./wait
father: pid==[111409] fpid==[91160]
child: pid==[111410] fpid==[111409]
Terminated
*/
return 9;
/*
* 不使用kill 信號
$ ./wait
father: pid==[112977] fpid==[91160]
child: pid==[112978] fpid==[112977]
wpid==[112978]
child normal exit,status==[9]
*
*/
}
return 0;
}
? waitpid函式
? 函式原型:
pid_t waitpid(pid_t pid, int *status, in options);
? 函式作用
同wait函式
? 函式引數
引數:
pid:
pid = -1 等待任一子行程,
pid > 0 等待其行程ID與pid相等的子行程,與wait等效,
pid = 0 等待行程組ID與目前行程相同的任何子行程,也就是說任何和呼叫
waitpid()函式的行程在同一個行程組的行程,
pid < -1 等待其組ID等于pid的絕對值的任一子行程,(適用于子行程在其他組的情況)
status: 子行程的退出狀態,用法同wait函式,
options:設定為WNOHANG,函式非阻塞,設定為0,函式阻塞,
? 函式回傳值
0:回傳回收掉的子行程ID;
-1:無子行程
=0:參3為WNOHANG,且子行程正在運行,
? waitpid函式練習
使用waitpid函式完成對子行程的回收
//父行程呼叫waitpid完成對子行程地回收 函式測驗
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>/*for wait*/
#include <unistd.h>
int main()
{
//創建子行程
//pid_t fork(void);
pid_t pid = fork();
if(pid<0)
{
perror("fork error");
return -1;
}
else if(pid>0)//父行程
{
printf("father: pid==[%d] fpid==[%d]\n",getpid(),getppid());
int status = 0;
//pid_t wpid = waitpid(pid,&status,0);//same to pid_t wpid = wait(&status);
while(1)//回圈等待子行程退出
{
pid_t wpid = waitpid(-1,&status,WNOHANG);//等待任一子行程,WNOHANG不阻塞
printf("wpid==[%d]\n",wpid);
if(wpid>0)
{
if(WIFEXITED(status))//正常退出
{
printf("child normal exit,status==[%d]\n",WEXITSTATUS(status));
}else if(WIFSIGNALED(status))//被信號殺死
{
printf("child killed by signal,status==[%d]\n",WTERMSIG(status));
}
}
else if(wpid==0)//子行程還活著
{
printf("child is living,wpid==[%d]\n",wpid);
}
else if(wpid==-1)//沒有子行程
{
printf("no child is living,wpid==[%d]\n",wpid);
break;
}
}
}
else if(pid == 0)//子行程
{
printf("child: pid==[%d] fpid==[%d]\n",getpid(),getppid());
sleep(2);
return 9;
}
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/279524.html
標籤:其他
