進程生命週期,進程生命週期建立、退出、中止,以及殭屍進程是什麼意思。linux
1、進程的定義數組
進程--線程。進程是資源分配單位;搞清楚進程就是搞清楚進程資源狀況。進程控制塊PCB是OS的通用叫法。task_struct結構體描述進程的資源狀況。以下圖所屬:數據結構
1)*mm描述內存資源ide
2)*fs:文件系統資源函數
3)文件資源:注意與fs的區別,打開文件的fd數組fd_array記錄打開文件的fd工具
4)*signal:該進程的信號處理函數(用戶理解爲多態)spa
5)pid:數量有限操作系統
節選自《linux操做系統原理與應用》:線程
傳統上,這樣的數據結構(task_struct)叫作進程控制塊PCB。linux中PCB是一個至關龐大的結構體,其域多達80多項,它的全部域按其功能可分爲如下幾類:3d
2、pid
1)pid數量有限,因此不能無限建立進程:32位-32768 64位-131072
2)fork炸彈的原理
改寫一下代碼
1 :() #函數定義 2 { 3 :|:& #調用本身,而後|管道,管道里面也遞歸調用:建立進程,而後&後臺執行 4 } 5 ; #函數結束 6 : #調用本身
|是管道,&是後臺執行。
一直在建立進程,把pid耗盡,kill、killall等命令也要建立一個進程執行,可是pid已經耗盡,沒法執行,用戶感受系統死掉。
3、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裏面這三種數據結構都有,使得各類場景快速達到目的,以空間換時間。
4、進程生命週期
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 }
kill -9 pid是殺不死殭屍進程的,由於殭屍進程已經死掉了。父進程一直不清理殭屍進程,能夠經過殺死殭屍進程的父進程來清理。
殭屍進程的資源已經釋放,因此不會形成內存泄漏。
工程中觀察進程是否內存泄漏:多點連續採樣法。震盪收斂沒有泄漏,震盪發散(上升)是內存泄漏。
殭屍太多也很差,佔用pid。
5)中止態:人爲中止進程,發送中止信號:1)ctrl+z,做業控制(JC),發送contine信號繼續運行(fg\bg),kill發送信號等;2)GDB調試;
cpulimit工具控制進程的cpu利用率:cpulimit -l 20 -p pid , 20爲容許的cpu利用率,實際結果不會那麼精
確。
5、 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 全英文
課後做業代碼地址: