1. 程式人生 > >任督二脈之進程管理(1)

任督二脈之進程管理(1)

動態 define 發送信號 aps 無限 _exit 情況 遞歸 技術

進程生命周期,進程生命周期創建、退出、停止,以及僵屍進程是什麽意思。

一、進程的定義

進程--線程。進程是資源分配單位;搞清楚進程就是搞清楚進程資源情況。進程控制塊PCB是OS的通用叫法。task_struct結構體描述進程的資源情況。如下圖所屬:

技術分享圖片

1)*mm描述內存資源

2)*fs:文件系統資源

3)文件資源:註意與fs的區別,打開文件的fd數組fd_array記錄打開文件的fd

4)*signal:該進程的信號處理函數(用戶理解為多態)

5)pid:數量有限

節選自《linux操作系統原理與應用》:

傳統上,這樣的數據結構(task_struct)叫做進程控制塊PCB。linux中PCB是一個相當龐大的結構體,其域多達80多項,它的所有域按其功能可分為以下幾類:

  • 狀態信息 描述進程的動態變化
  • 鏈接信息 描述進程的父子關系
  • 各種標識符 用簡單數字對進程進行標識
  • 進程間通信信息 描述多個進程在同一任務 上的協作工作
  • 時間和定時器信息 描述進程在生命周期內使用CPU時間的統計、計費等信息
  • 調度信息 描述進程優先級、調度策略等信息
  • 文件系統信息 對進程使用文件情況進行記錄
  • 虛擬內存信息 描述每個進程擁有的地址空間
  • 處理器環境信息 描述進程的執行環境(處理器的寄存器及堆棧等)

二、pid

1)pid數量有限,所以不能無限創建進程:32位-32768 64位-131072

技術分享圖片

2)fork炸彈的原理

改寫一下代碼

1 :() #函數定義
2 {
3     :|:&  #調用自己,然後|管道,管道裏面也遞歸調用:創建進程,然後&後臺執行
4 } 5 ; #函數結束 6 : #調用自己

|是管道,&是後臺執行。

一直在創建進程,把pid耗盡,kill、killall等命令也要創建一個進程執行,但是pid已經耗盡,無法執行,用戶感覺系統死掉。

三、task_struct管理

1)形成鏈表:最方便,但是進程之間的關系是樹型關系,父子進程關系,pstree命令可以查看,所以也可以用樹。

zsh@zsh-vm:~$ pstree
systemd─┬─ModemManager─┬─{gdbus}
        │              └─{gmain}
        ├─NetworkManager─┬─dhclient
        │                ├─dnsmasq
        │                ├─{gdbus}
        │                └─{gmain}
        ├─VGAuthService
        ├─accounts
-daemon─┬─{gdbus} │ └─{gmain} ├─acpid

2)形成樹:這樣可以反應進程之間的關系,找父子關系比較簡單,但是有時候需要檢索一個進程的pid,比如 kill -2 8934,這種情況下樹檢索比較慢了。使用哈希可以快速查找

3)形成哈希

總結:快速遍歷使用鏈表,想查找父子進程用樹,想通過pid快速查找進程用哈希。所以linux裏面這三種數據結構都有,使得各種場景快速達到目的,以空間換時間。

技術分享圖片

四、進程生命周期

技術分享圖片

1)就緒態:fork出來就是就緒態,linux裏面就緒和運行的狀態標誌是一樣的

2)運行態:linux裏面就緒和運行的狀態標誌是一樣的,時間片用完或者被搶占進入就緒態

3)睡眠態:等資源就進入睡眠態,等到資源就進入就緒態

4)僵屍態:進程死掉先成為僵屍,用於描述task_struct及成員還沒有消失,但是進程占用的資源已經消失;需要父進程wait4(waitpid等)等待僵屍才消失(父進程清理子進程)。所以僵屍狀態是很短的。

僵屍態的原因是父進程可以獲取子進程的退出碼exit_code,即退出原因。

技術分享圖片

例子:殺死子進程,觀察父進程能監控到子進程死亡原因。

技術分享圖片
 1 #include <stdio.h>
 2 #include <sys/wait.h>
 3 #include <stdlib.h>
 4 #include <unistd.h>
 5 
 6 int main()
 7 {
 8     pid_t pid, wait_pid;
 9     int status;
10     
11     pid = fork();
12     
13     if(pid == -1)
14     {
15         perror("Cannot create new process");
16         exit(1);
17     } else if (pid == 0)
18     {
19         printf("child process id: %ld\n", (long)getpid());
20         pause();
21         _exit(0);
22     } else 
23     {
24         #if 0 /* define 1 to make child always a zombie */
25         printf("ppid: %d\n", getpid());
26         while(1);
27         #endif
28         do
29         {
30             wait_pid = waitpid(pid, &status, WUNTRACED | WCONTINUED);
31             
32             if(wait_pid == -1)
33             {
34                 perror("cannot using waitpid function");
35                 exit(1);
36             }
37             
38             if(WIFEXITED(status))
39             {
40                 printf("child process exits, status = %d\n", WEXITSTATUS(status));
41             }
42             
43             if(WIFSIGNALED(status))
44             {
45                 printf("child process is killed by signal %d\n", WTERMSIG(status));
46             }
47             
48             if(WIFSTOPPED(status))
49             {
50                 printf("child process is stopped by signal %d\n", WSTOPSIG(status));
51             }
52             
53             if(WIFCONTINUED(status))
54             {
55                 printf("child process resume running...\n");
56             }
57             
58         }while(!WIFEXITED(status) && !WIFSIGNALED(status));
59         
60         exit(0);
61     }
62 }
View Code

kill -9 pid是殺不死僵屍進程的,因為僵屍進程已經死掉了。父進程一直不清理僵屍進程,可以通過殺死僵屍進程的父進程來清理。

僵屍進程的資源已經釋放,所以不會造成內存泄漏。

技術分享圖片

技術分享圖片

工程中觀察進程是否內存泄漏:多點連續采樣法。震蕩收斂沒有泄漏,震蕩發散(上升)是內存泄漏。

僵屍太多也不好,占用pid。

5)停止態:人為停止進程,發送停止信號:1)ctrl+z,作業控制(JC),發送contine信號繼續運行(fg\bg),kill發送信號等;2)GDB調試;

cpulimit工具控制進程的cpu利用率:cpulimit -l 20 -p pid , 20為允許的cpu利用率,實際結果不會那麽精

確。

技術分享圖片

五、 fork

1)先看一個例子,fork叉子

技術分享圖片

結果為打印6個(1*2+2*2):

2)fork返回值:子進程返回0,父進程返回子進程的pid。

技術分享圖片

運行結果:

父子進程哪個先跑默認不確定,但是有內核可調試開關/proc,傾向於讓子進程先跑。

3)子死父清場:linux裏面總是白發人送黑發人

技術分享圖片

4)深度睡眠:必須等到資源才能醒,不響應信號,所以kill -9也殺不死。why?major page fault,代碼段命運命中,還在硬盤,進程就進入深度睡眠,如果響應信號,那麽信號處理函數有可能也在硬盤,沒有載入內存,再次發生page fault,嵌套。中斷響應嗎?中斷是正在執行被中斷,已經睡眠了,怎麽中斷。

時鐘中斷也不可以喚醒。

淺度睡眠:資源來了醒,信號來了也可以醒。時鐘中斷可以喚醒。

睡眠是內核調用進入,驅動也可以。用戶態不可以直接調用睡眠。

答疑:getppid()獲取父進程的pid。

書籍:operating system three piecies 全英文

課後作業代碼地址:

技術分享圖片

任督二脈之進程管理(1)