中國(guó)建設(shè)銀行網(wǎng)站首頁下載自己怎么開網(wǎng)站
- 進(jìn)程的概念
- PCB是什么
- task_struct的作用
- 如何執(zhí)行進(jìn)程
- 進(jìn)程的探查
- 什么是bash
- ps命令的使用(查看進(jìn)程)
- 創(chuàng)建進(jìn)程
- 探究父子進(jìn)程
進(jìn)程的概念
簡(jiǎn)而言之,進(jìn)程就是正在在執(zhí)行的程序
之前說過,程序執(zhí)行的第一步Windows是雙擊程序Linux是 ./ ,系統(tǒng)接收到該命令時(shí)就會(huì)將磁盤中的程序代碼載入到內(nèi)存中,并為程序分配空間。
當(dāng)程序被加載到內(nèi)存后建立了自己的PCB,那他就是進(jìn)程了。
PCB是什么
PCB的概念:含有該進(jìn)程各種 信息 及 屬性 的 數(shù)據(jù)結(jié)構(gòu),比如進(jìn)程 ID ,用戶 ID ,組 ID ,進(jìn)程狀態(tài) ,優(yōu)先級(jí) ,I /O狀態(tài)信息及程序數(shù)據(jù)等。
PCB是一般課本上的稱呼(process control block), Linux操作系統(tǒng)下被稱為PCB的實(shí)體是: task_struct
task_struct的作用
task_struct 是 Linux內(nèi)核的一種數(shù)據(jù)結(jié)構(gòu),它會(huì)被裝載到 RAM(內(nèi)存) 里并且包含著進(jìn)程的信息
其包含內(nèi)容大致有:
1. 標(biāo)示符: 描述本進(jìn)程的唯一標(biāo)示符,用來區(qū)別其他進(jìn)程。
2. 狀態(tài): 任務(wù)狀態(tài),退出代碼,退出信號(hào)等。
3. 優(yōu)先級(jí): 相對(duì)于其他進(jìn)程的優(yōu)先級(jí)。
4. 程序計(jì)數(shù)器: 程序中即將被執(zhí)行的下一條指令的地址。
5. 內(nèi)存指針: 包括程序代碼和進(jìn)程相關(guān)數(shù)據(jù)的指針,還有和其他進(jìn)程共享的內(nèi)存塊的指針
6. 上下文數(shù)據(jù): 進(jìn)程執(zhí)行時(shí)處理器的寄存器中的數(shù)據(jù),可以理解為存儲(chǔ)的是程序已經(jīng)做了什么,下一步該做那些
8. I/ O狀態(tài)信息: 包括顯示的I/O請(qǐng)求,分配給進(jìn)程的I/ O設(shè)備和被進(jìn)程使用的文件列表。
9. 記賬信息: 可能包括處理器時(shí)間總和,使用的時(shí)鐘數(shù)總和,時(shí)間限制,記賬號(hào)等。其他信息等
如何執(zhí)行進(jìn)程
首先咱要明白,Linux 下你所有的 命令 與你能 執(zhí)行的操作 都與權(quán)限有關(guān)。
觸發(fā)任何一個(gè)事件,系統(tǒng)都會(huì)將其定義成一個(gè)進(jìn)程,并給予這個(gè)進(jìn)程一個(gè)專屬 ID ,稱為PID ,同時(shí)根據(jù)觸發(fā)這個(gè)進(jìn)程的用戶與相關(guān)屬性關(guān)系,給予該進(jìn)程PID設(shè)置對(duì)應(yīng)權(quán)限
運(yùn)行程序也一樣也要受到權(quán)限的約束,所以task_struct 要存有必要的屬性信息
正常情況下,task_struct會(huì)在內(nèi)存中像鏈表一樣依次排列,逐個(gè)進(jìn)行
,但我們要知道任何事情都要分個(gè)輕重緩急,操作系統(tǒng)在執(zhí)行進(jìn)程時(shí)更是如此。
所以進(jìn)程對(duì)應(yīng)的task_struct中便有了優(yōu)先級(jí)這一屬性,他用PRI值來表示優(yōu)先級(jí),PRI值越小則優(yōu)先級(jí)越高,所以下圖中PRI為60的會(huì)比PRI為80的優(yōu)先得到CPU的資源
優(yōu)先級(jí):是CPU分配資源的先后順序
上圖中PRI值只有兩種是為了大家方便理解,實(shí)際上PRI值是根據(jù)進(jìn)程屬性決定的(NI值也會(huì)影響進(jìn)程優(yōu)先級(jí)后邊會(huì)補(bǔ)充)
優(yōu)先級(jí)的必要性: 系統(tǒng)進(jìn)程數(shù)目眾多,而CPU資源只有少量,甚至1個(gè),所以進(jìn)程之間是具有競(jìng)爭(zhēng)屬性的。為了高效完成任務(wù),更合理競(jìng)爭(zhēng)相關(guān)資源,便具有了優(yōu)先級(jí)。
進(jìn)程的探查
說了那么多,是時(shí)候見見進(jìn)程了
在Linux下可用 ps 命令查看進(jìn)程
命令:ps
作用: 查看屬于當(dāng)前用戶的進(jìn)程
上圖可以看到輸入 ps 回車后只看到了當(dāng)前 ps 命令的進(jìn)程及 bash 的進(jìn)程,由此可以得出結(jié)論:命令只是某一程序快捷方式,執(zhí)行時(shí)也會(huì)創(chuàng)建進(jìn)程
什么是bash
每個(gè)用戶登錄時(shí)都會(huì)創(chuàng)建一個(gè) bash 進(jìn)程,各用戶之間的 bash 進(jìn)程互相之間沒有影響。
1. bash是一個(gè)命令處理器, 運(yùn)行在文本窗口中, 并能執(zhí)行用戶直接輸入的命令.
2. bash還能從文件中讀取Linux命令, 稱之為腳本.
3. bash支持通配符, 管道, 命令替換, 條件判斷等邏輯控制語句
總結(jié): bash可以稱為命令行解釋器,我么在命令行執(zhí)行的進(jìn)程都由他衍生而來。
ps命令的使用(查看進(jìn)程)
首先先了解進(jìn)程信息列表每一項(xiàng)分別表示什么
F :內(nèi)核分配給進(jìn)程的系統(tǒng)標(biāo)志
UID : 啟動(dòng)該進(jìn)程的用戶
PID : 進(jìn)程ID
PPID : 父進(jìn)程ID(如果該進(jìn)程是其他進(jìn)程啟動(dòng)的)
PRI : 進(jìn)程優(yōu)先級(jí)(值越小,優(yōu)先級(jí)越大)
NI :優(yōu)先級(jí)的修正值
VSZ : 進(jìn)程占用虛擬內(nèi)存空間的大小
RSS :進(jìn)程在未被交換出時(shí)占用的物理內(nèi)存大小
WCHAN :進(jìn)程休眠的內(nèi)核函數(shù)地址
STST : 代表當(dāng)前進(jìn)程狀態(tài)(R是可運(yùn)行正在等待;O是正在運(yùn)行;S代表休眠;Z代表僵化,已終止但找不到其父進(jìn)程 ;T代表停止)
上面簡(jiǎn)單演示了ps命令,但其只顯示了兩行極短的內(nèi)容這顯然不是咱想要的
下面演示ps的BSD風(fēng)格的指令
指令: ps la
作用:采用長(zhǎng)格式顯示與任意終端關(guān)聯(lián)的所有進(jìn)程
可以看到顯示了好幾個(gè)進(jìn)程,其中有兩個(gè)bash進(jìn)程,因?yàn)檫@臺(tái)現(xiàn)在有兩個(gè)賬號(hào)在登陸這。
其中右邊一欄 COMMAND 是程序名,圖中的./my_exe程序只是目前在另一個(gè)賬號(hào)上運(yùn)行的程序,其PID是19795,PPID表示父進(jìn)程./my_exe程序
PPID為18505,而18505恰好是bash的PID.
所以得出第二個(gè)結(jié)論:在Linux命令行執(zhí)行的命令,產(chǎn)生的進(jìn)程都由bash進(jìn)程衍生而來,也就是說命令行上執(zhí)行產(chǎn)生的進(jìn)程其PPID(父進(jìn)程)都為bash
下圖為ps的命令選項(xiàng),由于都是查詢類選項(xiàng)我就不一一示范了
選項(xiàng) | 描述 |
---|---|
T | 顯示與當(dāng)前終端關(guān)聯(lián)的所有進(jìn)程 |
a | 顯示與任意終端關(guān)聯(lián)的所有進(jìn)程 |
g | 顯示包括控制進(jìn)程在內(nèi)的所有進(jìn)程 |
r | 僅顯示運(yùn)行中的進(jìn)程 |
x | 顯示所有進(jìn)程,包括未分配任何終端的進(jìn)程 |
U userlist | 顯示屬于userlist列表中某個(gè)用戶ID所有的進(jìn)程 |
p pidlist | 顯示PID在pidlist列表中的進(jìn)程 |
t ttylist | 顯示與ttylist列表中的某個(gè)終端關(guān)聯(lián)的進(jìn)程 |
o format | 除了標(biāo)準(zhǔn)列,還輸出由 format指定的列 |
x | 以寄存器格式顯示數(shù)據(jù) |
z | 在輸出中包含安全信息 |
j | 顯示作業(yè)信息 |
l | 采用長(zhǎng)格式顯示 |
o format | 僅顯示由format指定的列 |
s | 采用信號(hào)格式顯示 |
u | 采用基于用戶的格式顯示 |
v | 采用虛擬內(nèi)存格式顯示 |
N namelist | 定義要在 wCHAN輸出列中顯示的值 |
o order | 定義信息列的顯示順序 |
s | 將子進(jìn)程的數(shù)值統(tǒng)計(jì)信息(比如CPU和內(nèi)存使用情況)匯總到父進(jìn)程中 |
c | 顯示真實(shí)的命令名稱(用以啟動(dòng)該進(jìn)程的程序名稱) |
e | 顯示命令使用的環(huán)境變量 |
f | 用層級(jí)格式來顯示進(jìn)程,顯示哪些進(jìn)程啟動(dòng)了哪些進(jìn)程 |
h | 不顯示頭信息 |
k sort | 指定用于排序輸出的列 |
n | 使用數(shù)值顯示用戶ID、組ID以及 wCHAN信息 |
w | 為更寬的終端屏幕生成寬輸出 |
H | 將線程顯示為進(jìn)程 |
m | 在進(jìn)程之后顯示線程 |
L | 列出所有的格式說明符 |
v | 顯示ps命令的版本 |
創(chuàng)建進(jìn)程
方法:進(jìn)程可使用系統(tǒng)調(diào)用 fork() 函數(shù)創(chuàng)建新進(jìn)程。
其中調(diào)用 fork() 的進(jìn)程被稱為父進(jìn)程,新創(chuàng)建的進(jìn)程被稱為子進(jìn)程
如下:在main中創(chuàng)建一個(gè)子進(jìn)程
遠(yuǎn)行結(jié)果如下
如上所示使用 fork() 創(chuàng)建了子進(jìn)程后,bbbbbb…居然被打印了兩次,而aaaa…輸出正常只打印了一次
為探究為什么咱使用兩個(gè)函數(shù)輔助咱們觀看結(jié)果
函數(shù):getpid()
作用:返回當(dāng)前進(jìn)程PID
函數(shù):getppid()
作用:返回當(dāng)前進(jìn)程PPID(父進(jìn)程)
重新對(duì)代碼編輯如下:
#include<unistd.h>
#include<stdio.h> int main() { printf("aaaaaaaaaaaaaaaaaaa\n"); fork(); //創(chuàng)建一個(gè)子進(jìn)程 printf("我的PID :%d 我的PPID :%d \n",getpid(),getppid()); return 0; }
執(zhí)行程序后結(jié)果如下
可以看出第一個(gè)打印出自己PID 6389 的為父進(jìn)程 , 因?yàn)榈诙€(gè)打印出自己的PPID 為 6389,所以PID 6390為子進(jìn)程
但也說明了父子進(jìn)程執(zhí)行的代碼是一樣的。
探究父子進(jìn)程
查看 fork 的說明:
1:如果子進(jìn)程開啟成功則給父進(jìn)程返回子進(jìn)程的PID,否則返回-1
2:會(huì)給子進(jìn)程返回0
由此我下下以下程序:
1 #include<unistd.h>2 #include<stdio.h>3 int main()4 {5 int n = 5;6 int i = 1;7 printf("aaaaaaaaaaaaaaaaaaa\n");8 int pp = fork(); //創(chuàng)建一個(gè)子進(jìn)程9 if(pp == 0)//子進(jìn)程程序10 {11 while(n--)12 {13 printf("我是子進(jìn)程,i = %d 我的PID :%d 我的PPID :%d \n",i ,getpid(),getppid());14 sleep(1); i =99;//把值改掉15 }16 }17 else18 { 19 while(n--)20 { 21 printf("我是父進(jìn)程,i = %d 我的PID :%d 我的PPID :%d \n",i ,getpid(),getppid()); sleep(1);22 } 23 }24 return 0;25 }
如上圖 pp 變量會(huì)接收 fork() 的返回值(目前不考慮進(jìn)程創(chuàng)建失敗的情況),上面已經(jīng)敘述了父進(jìn)程與子進(jìn)程的代碼是一致的 ,只是父進(jìn)程中 pp 變量接收到的 fork() 返回值為其子進(jìn)程的PID ,而子進(jìn)程中的 pp 變量接收到的 fork() 返回值為0
所以上述代碼中,子進(jìn)程和父進(jìn)程所執(zhí)行的代碼一致(子進(jìn)程從fork()函數(shù)位置開始執(zhí)行),只是 pp 變量不同
大致可以如下圖
程序執(zhí)行結(jié)果如下
和我們預(yù)想的一致,由于父子進(jìn)程中的 pp 變量不同所以被 if 和 else 區(qū)分打印出了對(duì)應(yīng)的
但程序代碼的第 14 行,在子進(jìn)程中把 i 的值改成了99,但父進(jìn)程的i值并沒有被改變
總結(jié):內(nèi)核通過對(duì)父進(jìn)程的復(fù)制來創(chuàng)建子進(jìn)程,子進(jìn)程從父進(jìn)程處繼承數(shù)據(jù)段,棧段,以及堆段的副本后,可以修改這些內(nèi)容,不會(huì)影響父進(jìn)程的內(nèi)容(在內(nèi)存中被標(biāo)記為只讀的程序文本段則由父,子進(jìn)程共享);