進程的相關知識筆記:
進程是一個程序的執行過程。多個進程分時複用CPU,當分配給進程的時間片結束後,內核會收回進程對CPU的使用權,轉而給系統的其他進程執行,而之前的進程就需要進入睡眠態,相關的數據就會先保存起來,等候CPU的調度。所以一個進程的生命週期有很多不同的狀態,通常進程的狀態被劃分爲5種:初始態、就緒態、運行態、睡眠態、終止態。
在系統中每一個進程都有一個進程id,簡稱pid (process id),進程有父子關係、兄弟關係,每一個進程都有一個父親,父進程的進程id,叫做ppid。所以系統裏面的進程會形成一個進程樹,使用pstree命令可以查看當前系統的進程樹。以前進程的頂端是init進程,進程號爲1,現在有的linux系統使用systemd作爲系統的頂級進程,進程號也是1,至於兩者的區別,可以谷歌查閱相關的資料,當我們fork一個進程後,代碼從fork後,分別由兩個進程執行,父子進程的執行順序無法預測。當子進程執行完,父進程沒有進行回收處理,就會出現殭屍進程(defunct進程),當父進程執行完,子進程還沒執行完,子進程就變成孤兒進程,這是systemd就會認領,負責回收處理。
下面就是一個利用fork函數,創建子進程的例子:
#include <stdio.h> //標準的輸入輸出函數
#include <stdlib.h> //standard library標準庫函數頭文件
#include <unistd.h> //對於類 Unix 系統,unistd.h 中所定義的接口通常都是大量針對系統調用的封裝 fork、
int main()
{
pid_t pid;
pid=fork(); //創建一個進程,下面的代碼, 由兩個進程分別執行,父子進程執行順序無法預測
// pid 在兩個不同的進程中,返回的結果不一樣
// 這是異常情況
if (pid==-1)
{
perror("fork失敗!");
exit(1);
}
//返回大於0的進程就是父進程
if(pid>0) //父進程
{
printf("父進程: pid= %d , ppid=%d,子進程: %d \n", getpid(),getppid(),pid);
sleep(1); //這裏延遲父進程程序,等子進程先執行完。
}
else if(pid==0) //子進程
{
printf("子進程: pid= %d , ppid=%d \n", getpid(),getppid());
}
printf("執行完成!\n"); //由兩個進程執行,當然輸出兩次
return 0; //養成好習慣,返回程序執行狀態碼
}
請留意sleep(1); 這段代碼, 並嘗試註釋後,重新編譯一個,然後執行他們,看看有加sleep和沒有的區別,
有加sleep(1);會輸出:
父進程: pid= 17571 , ppid=16415,子進程: 17572
子進程: pid= 17572 , ppid=17571
執行完成!
執行完成!
注: 子進程先執行完,父進程還沒死,此時子進程ppid就是父進程的pid
沒有加sleep;可能會輸出:
父進程: pid= 17580 , ppid=16415,子進程: 17581
執行完成!
子進程: pid= 17581 , ppid=1
執行完成!
注: 父進程先執行完,子進程還沒,子進程被systemd接收,子進程的ppid就變成了1。
本文參考Linux編程基礎一書。