一、進程的基本概念
在給進程下定義之前,我們先了解一下進程:
我們在編寫完代碼并運行起來時,在我們的磁盤中會形成一個可執行文件,當我們雙擊這個可執行文件時(程序時),這個程序會加載到內存中,而這個時候我們不能把它叫做程序了,應該叫做進程。所以說,只要把程序(運行起來)加載到內存中,就稱之為進程。
進程的概念:程序的一個執行實例,正在執行的程序等
二、進程描述—PCB
PCB:進程控制塊(結構體)
當一個程序加載到內存中,操作系統要為剛剛加載到內存的程序創建一個結構體(PCB),進程信息被放在這個結構體中(PCB),可以理解為PCB是進程的屬性的集合。
在Linux操作系統下的PCB是:task_struct
task_struct是Linux內核的一種數據結構,它會被裝載到RAM(內存)里并且包含著進程的信息
在進程執行時,任意時間內,進程對應的PCB都要以下內容:
- 標示符:描述本進程的唯一標示符,用來區別其他進程
- 狀態:任務狀態
- 優先級:相對于其他進程的優先級
- 程序計數器:程序中即將被執行的下一條指令的地址
- 內存指針:包括程序代碼和進程相關數據的指針,還有和其他進程共享的內存塊指針
- 上下文數據:進程執行時處理器的寄存器中的數據
- I/O狀態信息:包括顯示的I/O請求,分配給進程的I/O設備和被進程使用的文件列表
- 記賬信息:可能包括處理器時間總和,使用的時鐘數總和,時間限制,記賬號等
- 其他信息:…
優先級的理解:
由于CPU只要一個,進程可以有多個,所以CPU的資源有限,操作系統在調度進程到CPU時會根據進程的優先級來判斷。
程序計數器的理解:
CPU跑一個進程時,要執行它的代碼,而代碼是自上往下執行的(if、else、循環等除外),CPU先要取指令,然后分析指令,再然后執行指令。取完一個指令后,CPU中的寄存器(EIP指令寄存器)會保存當前指令的下一條指令的地址,方便下次取下一個指令。
所謂的函數跳轉、分支判斷、循環等,都是修改EIP完成的。
上下文數據的理解:
CPU在跑一個進程時,沒有跑完就開始切換其他進程,為了下次繼續跑完這個進程,會保留這個進程的上下文數據,當這個進程回來時,會把上下文數據移動到CPU內部繼續執行。
三、通過系統調用獲取進程標示符
#include<stdio.h>
#include<unistd.h>
int main()
{while(1){printf("i am process...pid:%d,ppid:%d\n",getpid(),getppid());sleep(1);}
return 0;}
通過ps aux | grep 文件名
來找
其中getpid()
是找進程的標示符,getppid()
找父進程的標示符
四、通過系統調用創建進程——fork
fork函數可以創建一個子進程
#include<stdio.h>
#include<unistd.h>
int main()
{pid_t id=fork();//創建子進程while(1){if(id==0){printf("i am process...child---pid:%d,ppid:%d\n",getpid(),getppid());sleep(1);}else if(id>0){printf("i am process..father---pid:%d,ppid:%d\n",getpid(),getppid());sleep(1);}else{;}}return 0;
}
我們可以得出:這段代碼有兩個進程,并且它們的關系是父子關系。
什么是fork函數:在調用fork函數之前,只有一個進程(父進程),當這個進程調用fork函數之后,fork函數會復制一個進程(子進程),區別是PID不同,它們的關系是父子關系。
fork函數會返回兩次值:
——給父進程返回子進程的pid。
——給子進程返回0。
——失敗時,在父進程中返回-1,不創建子進程,并且errno被適當地設置。
五、進程的狀態
操作系統存在著五種狀態模型:
- 新建態:剛剛創建的進程,操作系統還沒有把它加入可執行進程組中。
- 就緒態:進程已經做好準備,只有有機會就會開始執行。
- 運行態:該進程正在執行。
- 阻塞態:進程在某些事件發生前不能執行,如I/O操作完成。
- 退出態:操作系統從可執行進程組中釋放出進程,或者自身停止,或者是因為某些原因被取消。
R 可執行狀態
通過命令 ps aux 可以查看進程的狀態
【注意】此可執行狀態并非上面的運行態。
進程中的R狀態不代表正在運行,代表的可被調度,此運行相當于上面的就緒態。
操作系統會把進程中R狀態的進程全放在調度隊列中,方便調度。
S 睡眠狀態
(1)創建一個可執行態
#include<stdio.h>
#include<unistd.h>
int main()
{while(1);return 0;
}
(2)創建休眠態進程
#include<stdio.h>
#include<unistd.h>
int main()
{while(1)sleep(10);return 0;
}
S狀態是淺度睡眠,隨時可以被喚醒,也可以被殺掉。
D 磁盤休眠狀態
可以表示為深度睡眠,該進程不會被殺掉,即使你是操作系統,除非我自動喚醒,才可以恢復。
這種狀態(D)的進程殺不死。
T 暫停狀態
向進程發送SIGSTOP信號,該進程會響應該信號進入暫停狀態,
向該進程發送SIGCONT信號,該進程會從暫停狀態恢復到可執行狀態。
X 死亡狀態 & Z 僵尸狀態
僵尸狀態:一個處于僵尸狀態的進程,會等待它的父進程或操作系統對它的信息進行讀取,之后才會被釋放。
通過代碼來模擬僵尸狀態的進程:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>int main()
{pid_t id=fork();int count=5;while(1){if(id==0){while(count){printf("i am process..child---.pid:%d,ppid:%d\n,count: %d",getpid(),getppi d(),--count);sleep(1);}printf("child quit....\n");exit(1);}else if(id>0){printf("i am process..father---pid:%d,ppid:%d\n",getpid(),getppid());sleep(1);}}return 0;}
用?while :; do ps aux |head -1&&ps aux|grep a.out; echo "#######################";sleep 1;done?
來監控進程的狀態。
死亡狀態:進程被操作系統釋放了或者自己退出了
六、僵尸進程
當一個進程變為僵尸狀態的時候,該進程就變成了僵尸進程。
- 僵死狀態(Zombies)是一個比較特殊的狀態。當進程退出并且父進程沒有讀取到子進程退出的返回代碼時就會產生僵死(尸)進程
- 僵死進程會以終止狀態保持在進程表中,并且會一直在等待父進程讀取退出狀態代碼。
- 所以,只要子進程退出,父進程還在運行,但父進程沒有讀取子進程狀態,子進程進入Z狀態。
僵尸進程的危害
七、孤兒進程
在Linux中,進程的關系主要是父子關系。
一對父子進程中的父進程退出了,子進程還在運行,就會形成孤兒進程。
如果沒有進程來回收該子進程的信息,那么會變成僵尸狀態,會存在內存泄漏的問題。
為了解決這個問題,該子進程會立即被1號init進程領養。
通過代碼來模擬孤兒狀態的進程:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>int main()
{pid_t id=fork();int count=5;while(1){if(id==0){while(1){printf("i am process..child---.pid:%d,ppid:%d\n,count: %d",getpid(),getppid(),--count);sleep(1);}printf("child quit....\n");exit(1);}else if(id>0){while(count){printf("i am process..father---pid:%d,ppid:%d\n",getpid(),getppid()); count--;sleep(1);}exit(0);}}return 0;}
用?while :; do ps axj |head -1 && ps axj | grep a.out;echo "#######################";sleep 1;done?
來監控進程的狀態。
觀察子進程的PPID
通過查看該子進程的信息,可以得知該進程被1號init進程領養。
八、進程優先級
基本概念
CPU中的資源是有限的,不可能多個進程一起在CPU上運行,利用優先級把進程有效的先后排好,改善了系統的性能。
- cpu資源分配的先后順序,就是指進程的優先權(priority)
- 優先權高的有優先執行權。
查看進程優先級
用?ps -l?
可以查看到進程的優先級
PRI:表示這個進程被執行的優先級,其值越小越早執行
NI:表示這個進程的nice值
PIR and NI
nice值表示進程可被執行的優先級的修正值。
PIR=PIR(old)+nice。
當nice為負值時,那么該進程的優先級值會變小,優先級會變高,進程越快被執行。
當然,nice也是有范圍的,-20~19,一共40個級別。
用top命令更改已存在的進程的nice
top
命令
接著按r
然后輸入進程的PID
輸入nice
值
其他
- 競爭性:系統進程數目多,而CPU的資源有限,所以進程之間是具有競爭屬性的。為了高效完成任務,更合理的競爭相關資源,便有了優先級
- 獨立性:多進程運行,需要獨享各種資源,多進程運行期間互不干擾
- 并行:多個進程在多個CPU下分別,同時進行運行,這稱之為并行
- 并發: 多個進程在一個CPU下采用進程切換的方式,在一段時間之內,讓多個進程都得以推進,稱之為并發