文章目錄
- 1.Linux行程
- 1.1行程概念:
- 1.2行程狀態:
- 2.fork()函式
- 2.1概述:
- 代碼示例:
- 2.2 運行結果:
- 2.3總結:
- 3.僵尸行程
- 3.1代碼模擬僵尸行程:
- 3.2僵尸行程結果展示:
- 3.3僵尸行程危害:
- 4.孤兒行程
- 4.1代碼模擬孤兒行程:
- 4.2孤兒行程結果展示:
- 4.3總結:
1.Linux行程
1.1行程概念:
- 從用戶角度:行程就是一個正在運行中的程式,
- 作業系統角度:作業系統運行一個程式,需要描述這個程式的運行程序,這個描述通過一個結構體task_struct{}來描述,統稱為PCB,因此對作業系統來說行程就是PCB(process control block)程式控制塊
- 行程的描述資訊有:識別符號PID,行程狀態,優先級,程式計數器,背景關系資料,記憶體指標,IO狀態資訊,記賬資訊,都需要作業系統進行調度,
1.2行程狀態:
/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
2.fork()函式
2.1概述:
使用 fork() 函式得到的子行程是父行程的一個復制品,它從父行程處繼承了整個行程的地址空間:
包括行程背景關系(行程執行活動全程序的靜態描述)、行程堆疊、打開的檔案描述符、信號控制設定、行程優先級、行程組號等,子行程所獨有的只有它的行程號,計時器等(只有小量資訊),
pid_t fork(void);
頭檔案:
#include <sys/types.h>
#include <unistd.h>
功能:
- 用于從一個已存在的行程中創建一個新行程,新行程稱為子行程,原行程稱為父行程,
回傳值:
- 成功:子行程中回傳 0,父行程中回傳子行程 ID,pid_t,為無符號整型,
- 失敗:回傳 -1,
代碼示例:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
pid_t pid;
pid = fork();
if( pid < 0 ){ // 沒有創建成功
perror("fork");
}
if(0 == pid){ // 子行程
while(1){
printf("I am son\n");
sleep(1);
}
}
else if(pid > 0){ // 父行程
while(1){
printf("I am father\n");
sleep(1);
}
}
return 0;
}
2.2 運行結果:

2.3總結:
- 通過運行結果,可以看到,父子行程各做一件事(各自列印一句話),這里,我們只是看到只有一份代碼,實際上,fork()
以后,有兩個地址空間在獨立運行著,有點類似于有兩個獨立的程式(父子行程)在運行著,需要注意的是,在子行程的地址空間里,子行程是從fork() 這個函式后才開始執行代碼, - 在 fork() 之后是父行程先執行還是子行程先執行是不確定的,這取決于內核所使用的調度演算法,
3.僵尸行程
一個行程使用 fork 創建子行程,如果子行程退出而父行程并沒有呼叫 wait() 或者 waitpid() 獲取子行程資訊,那么子行程的描述符仍然保存在系統中,這種行程就被稱為僵尸行程,
Z 行程
3.1代碼模擬僵尸行程:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
printf("輸入一遍\n");
pid_t ret = fork();
if(ret > 0)
{
//parent
while(1)
{
printf("I am parent! pid is : %d\n", getpid());
sleep(1);
}
}
else if(ret == 0)
{
/child
int count = 0;
while(count<5)
{
printf("I am child! pid is : %d, ppid: %d\n", getpid(), getppid());
count++;
sleep(2);
}
exit(0);
}
else
{
printf("fork error\n");
}
sleep(1);
return 0;
}
3.2僵尸行程結果展示:

3.3僵尸行程危害:
子行程的退出狀態會一直被維持下去,維護退出狀態本身就是要用資料維護,也屬于行程基本資訊,被保存在
task_struct中,也就是說只要Z狀態不退出,那么PCB要一直維護退出資訊,如果一個父行程創建了很多的子行程,都不進行回收,就會造成記憶體資源的極大浪費,也會造成記憶體泄露,
4.孤兒行程
父行程提前退出,子行程就稱為“孤兒行程”,一旦父行程退出,子行程要退出的時候就是Z狀態,因為沒有行程接收它的退出資訊,所以孤兒行程要被1號init行程領養回收,從而避免子行程變為僵尸行程,
4.1代碼模擬孤兒行程:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t ret = fork();
if(ret < 0)
{
printf("創建行程失敗!\n");
}
else if(ret > 0)
{
int count = 0;
while(count++ < 5)
{
printf("我是父行程(id:%d)\n",getpid());
sleep(2);
}
exit(0);
}
else
{
while(1)
{
printf("我是子行程(id:%d)\n",getpid());
sleep(1);
}
}
sleep(1);
return 0;
}
4.2孤兒行程結果展示:

4.3總結:
os考慮了這種情況的發生,在父行程退出,子行程還在運行(子行程被稱為孤兒行程)的時候重新給他找一個父親,如圖所示就是1號行程systemd,
1號行程(init)擴展:
由0行程創建,完成系統的初始化. 是系統中所有其它用戶行程的祖先行程,
Linux中的所有行程都是有init行程創建并運行的,首先Linux內核啟動,然后在用戶空間中啟動init行程,再啟動其他系統行程,在系統啟動完成完成后,init將變為守護行程監視系統其他行程,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/267160.html
標籤:其他
上一篇:流水線-流水線相關計算
下一篇:SSL協議原理
