linux系统编程之进程概念(操作系统---管理,进程创建,进程状态,进程优先级, 环境变量,程序地址空间,进程O(1)调度方法)
系統(tǒng)編程:
進程概念->進程控制->基礎(chǔ)IO->進程間通信->進程信號->多線程進程概念
馮諾依曼體系結(jié)構(gòu)----現(xiàn)代計算機硬件體系結(jié)構(gòu)
馮諾依曼體系結(jié)構(gòu)----現(xiàn)代計算機硬件體系結(jié)構(gòu)
關(guān)于馮諾依曼,必須強調(diào)幾點:
- 這里的存儲器指的是內(nèi)存 不考慮緩存情況,
- 這里的CPU能且只能對內(nèi)存進行讀寫,
- 不能訪問外設(shè)(輸入或輸出設(shè)備) 外設(shè)(輸入或輸出設(shè)備)要輸入或者輸出數(shù)據(jù),也只能寫入內(nèi)存或者從內(nèi)存中讀取。
- 一句話,所有設(shè)備都只能直接和內(nèi)存打交道。
對馮諾依曼的理解,不能停留在概念上,要深入到對軟件數(shù)據(jù)流理解上,請解釋,從你登錄上qq開始和某位朋友聊 天開始,數(shù)據(jù)的流動過程。從你打開窗口,開始給他發(fā)消息,到他的到消息之后的數(shù)據(jù)流動過程。如果是在qq上發(fā) 送文件呢?
硬件決定了軟件的行為
操作系統(tǒng)—管理
操作系統(tǒng):
目的:
為了讓計算機更加好用—功能:合理統(tǒng)籌管理計算機上邊的軟硬件資源管理:
先描述使用pcb描述進程,使用雙向鏈表將pcb串起來進行管理,再組織。庫函數(shù)與系統(tǒng)調(diào)用接口的關(guān)系:
封裝關(guān)系:庫函數(shù)封裝了系統(tǒng)調(diào)用接口,是上下級的調(diào)用關(guān)系進程概念----進程是什么
進行中的程序
linux是一個多任務(wù)操作系統(tǒng),表示有大量的程序需要被cpu調(diào)度運行,這時候cpu使用了分時技術(shù),分別輪詢處理每一個進程,在進程程序切換調(diào)度時,需要記錄運行信息,因此操作系統(tǒng)在調(diào)度進程在cpu上運行時,使用pcb對運行中的程序進行描述,通過調(diào)度pcb完成對進程的調(diào)度,因此進程是pcb。
pcb對運行中程序進行描述
每一個運行的程序都是pcb
在操作系統(tǒng)角度,操作系統(tǒng)通過pcb來控制一個進程的運行,這個pcb也叫進程描述符,描述了一個運行中的程序
Linux操作系統(tǒng)下的PCB是task_struct結(jié)構(gòu)體(用雙向鏈表進行組織的)
什么時task_struct結(jié)構(gòu)體
參考鏈接
task_struct結(jié)構(gòu)體中的內(nèi)容
- 標示符: 描述本進程的唯一標示符,用來區(qū)別其他進程。
- 狀態(tài): 任務(wù)狀態(tài),退出代碼,退出信號等。
- 優(yōu)先級: 相對于其他進程的優(yōu)先級。
- 程序計數(shù)器: 程序中即將被執(zhí)行的下一條指令的地址。
- 內(nèi)存指針: 包括程序代碼和進程相關(guān)數(shù)據(jù)的指針,還有和其他進程共享的內(nèi)存塊的指針
- 上下文數(shù)據(jù): 進程執(zhí)行時處理器的寄存器中的數(shù)據(jù)[休學(xué)例子,要加圖CPU,寄存器]。
- I/O狀態(tài)信息: 包括顯示的I/O請求,分配給進程的I/O設(shè)備和被進程使用的文件列表。
- 記賬信息: 可能包括處理器時間總和,使用的時鐘數(shù)總和,時間限制,記賬號等。
- 其他信息
內(nèi)存指針
pcb中有一個指針指向了當(dāng)前要運行的程序 cpu通過pcb內(nèi)存指針知道代碼在什么位置,然后加載到內(nèi)存上面cpu分時機制
不會體會到卡頓的原因,調(diào)度進程時,不會一直在一個進程上面運行,輪詢調(diào)度pcb 。 每個都執(zhí)行一段時間,切換速度很快。 每個進程只運行很短的一段時間(時間片)程序計數(shù)器
即將執(zhí)行的指令的地址上下文數(shù)據(jù)
cpu正在處理的數(shù)據(jù)是什么標識符PID
每一個進程都有一個ID進程狀態(tài)
當(dāng)前進程處于什么狀態(tài)優(yōu)先級
前臺進程(交互式進程)優(yōu)先級更高 批處理(后臺進程)IO狀態(tài)信息
每一個進程里面都會打開很多的文件,打開文件就要進行管理 記錄描述文件,所以需要保存下來這些信息記賬信息
一個進程大致在cpu上運行了多長時間進程查看
ps
-ef -aux 查看系統(tǒng)所有進程信息- /proc 保存系統(tǒng)中正在運行的程序信息
- pid_t getpid() 獲取調(diào)用進程的pid
- 根目錄下的proc/目錄存放的就是當(dāng)前操作系統(tǒng)上面正在運行中的程序的運行信息
例如
#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main() { while(1){ sleep(1); } return 0; }通過系統(tǒng)調(diào)用獲取進程標示符
#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main() { printf("pid: %d\n", getpid()); printf("ppid: %d\n", getppid()); return 0; }進程創(chuàng)建
創(chuàng)建進程就是創(chuàng)建pcb
用fork創(chuàng)建進程
fork()—通過復(fù)制調(diào)用進程(父進程)創(chuàng)建一個新的進程(子進程)
子進程與父進程完全相同
head line 打印了一次
tail line 打印了兩次
復(fù)制了父進程的pcb(意味著和父進程擁有一樣的內(nèi)存指針,程序計數(shù)器,上下文數(shù)據(jù)):
和父進程運行相同的代碼,相同的運行位置,
處理一樣的數(shù)據(jù)
父子進程代碼共享,數(shù)據(jù)獨有 。
同一個內(nèi)存區(qū)域,打印的值相同
子進程創(chuàng)建成功都是從下一步指令開始運行
如何分辨父子進程:通過返回值
父子進程不一定誰先運行,要看cpu調(diào)哪個pcb
父進程:
子進程:
返回0失敗:
返回-1為什么要創(chuàng)建子進程?意義何在?
進程狀態(tài)
普遍的系統(tǒng)的三種狀態(tài)
就緒,運行,阻塞
Linux進程狀態(tài):
加號代表前臺進程
cpu使用率非常高,什么原因?
死循環(huán)。
殺死進程
kill 進程ID普通殺死進程殺不死停止態(tài)進程
要用強殺
僵尸進程:
處于僵死態(tài)的進程----進程退出后,資源沒有完全釋放(沒有完全退出)
強殺都殺不死
如何產(chǎn)生?
子進程先于父進程退出,將自己退出原因保存在pcb中,操作系統(tǒng)檢測到子進程退出,因為父進程有可能關(guān)注退出原因,所以不敢隨意釋放所有資源,通知父進程子進程的退出,但是這時父進程可能正在打麻將,沒有關(guān)注到這個通知,導(dǎo)致子進程退出了
但是資源一直沒有 釋放,處于僵尸進程,處于僵死狀態(tài),成為僵尸進程。
危害:資源泄露,一個用戶能夠創(chuàng)建的進程是有限的,導(dǎo)致新進程創(chuàng)建失敗
處理:干掉父進程
如何避免:
孤兒進程:
父進程先于子進程退出,子進程成為孤兒進程,運行在操作系統(tǒng)后臺,父進程成為1號進程(被領(lǐng)養(yǎng))孤兒進程的使命就是不斷奮斗最后成為守護進程
守護進程/精靈進程
進程優(yōu)先級
通過一個評級來決定一個進程的cpu資源優(yōu)先分配權(quán)
為了讓計算機運行的更加合理
(因為進程的性質(zhì)各有不同—批處理/交互式)
查看:
修改:優(yōu)先級無法直接修改,但是可以通過修改NI的值,來調(diào)整PRI的值
PRI=PRI+NI
renice程序運行后修改 (nice的范圍(-20~19))
nice程序運行時指定
nice -n ni_val ./main優(yōu)先級調(diào)整更多的是針對cpu密集型程序(對cpu資源要求比較高)
磁盤密集型程序因為本事呢對cpu資源要求不是很高,因此大多數(shù)情況下,沒必要調(diào)整
我們很容易注意到其中的幾個重要信息,有下:
PRI and NI
PRI也還是比較好理解的,即進程的優(yōu)先級,或者通俗點說就是程序被CPU執(zhí)行的先后順序,此值越小 進程的優(yōu)先級別越高那NI呢?就是我們所要說的nice值了,其表示進程可被執(zhí)行的優(yōu)先級的修正數(shù)值 PRI值越小越快被執(zhí)行,那么加入nice值后,將會使得PRI變?yōu)?#xff1a;PRI(new)=PRI(old)+nice這樣,當(dāng)nice值為負值的時候,那么該程序?qū)?yōu)先級值將變小,即其優(yōu)先級會變高,則其越快被執(zhí)行 所以,調(diào)整進程優(yōu)先級,在Linux下,就是調(diào)整進程nice值 nice其取值范圍是-20至19,一共40個級別需要強調(diào)一點的是,進程的nice值不是進程的優(yōu)先級,他們不是一個概念,但是進程nice值會影響到進 程的優(yōu)先級變化。可以理解nice值是進程優(yōu)先級的修正修正數(shù)據(jù)用top命令更改已存在進程的nice
top 進入top后按“r”–>輸入進程PID–>輸入nice的值競爭性:
系統(tǒng)進程數(shù)目眾多,而CPU資源只有少量,甚至1個,所以進程之間是具有競爭屬性的。為了高 效完成任務(wù),更合理競爭相關(guān)資源,便具有了優(yōu)先級
獨立性:
多進程運行,需要獨享各種資源,多進程運行期間互不干擾
并行:
多個進程在多個CPU下分別,同時進行運行,這稱之為并行
并發(fā):
多個進程在一個CPU下采用進程切換的方式,在一段時間之內(nèi),讓多個進程都得以推進,稱之為 并發(fā)
環(huán)境變量
環(huán)境變量(environment variables)一般是指在操作系統(tǒng)中用來指定操作系統(tǒng)運行環(huán)境的一些參數(shù) 如:我們在編寫C/C++代碼的時候,在鏈接的時候,從來不知道我們的所鏈接的動態(tài)靜態(tài)庫在哪里,但 是照樣可以鏈接成功,生成可執(zhí)行程序,原因就是有相關(guān)環(huán)境變量幫助編譯器進行查找。 環(huán)境變量通常具有某些特殊用途,還有在系統(tǒng)當(dāng)中通常具有全局特性就是內(nèi)存解釋
和環(huán)境變量相關(guān)的命令
環(huán)境變量的組織方式
每個程序都會收到一張環(huán)境表,環(huán)境表是一個字符指針數(shù)組,每個指針指向一個以’\0’結(jié)尾的環(huán)境字符串
常見環(huán)境變量:HOME SHLL PATH
通過第三方變量environ獲取
**int argc 參數(shù)個數(shù)
char argv[] 字符串指針數(shù)組放的是參數(shù)
char env[] 這個字符串指針數(shù)組所保存的就是環(huán)境變量
通過系統(tǒng)調(diào)用獲取或設(shè)置環(huán)境變量
#include <stdio.h> #include <stdlib.h>int main() { printf("%s\n", getenv("PATH")); return 0; }環(huán)境變量通常是具有全局屬性的
環(huán)境變量通常具有全局屬性,可以被子進程繼承下去
#include <stdio.h> #include <stdlib.h>
int main() { char * env = getenv("MYENV"); if(env){ printf("%s\n", env); } return 0;}直接查看,發(fā)現(xiàn)沒有結(jié)果,說明該環(huán)境變量根本不存在
導(dǎo)出環(huán)境變量 export MYENV=“hello world”
再次運行程序,發(fā)現(xiàn)結(jié)果有了!說明:環(huán)境變量是可以被子進程繼承下去的!想想為什么?
程序地址空間
為什么要用虛擬地址空間+頁表:保持進程獨立性+充分利用內(nèi)存+內(nèi)存訪問控制
段頁式內(nèi)存管理:段號+段內(nèi)地址+頁內(nèi)偏移
段式內(nèi)存管理:段號+段內(nèi)地址
頁式內(nèi)存管理:頁號+頁內(nèi)偏移
#include <stdio.h> #include <unistd.h> #include <stdlib.h>
int g_val = 0;
int main(){ pid_t id = fork(); if(id < 0){ perror("fork"); return 0; }else if(id == 0){ //childprintf("child[%d]: %d : %p\n", getpid(), g_val, &g_val); }else{ //parent printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val); } sleep(1); return 0; }
我們發(fā)現(xiàn),輸出出來的變量值和地址是一模一樣的,很好理解呀,因為子進程按照父進程為模版,父子并沒有對變 量進行進行任何修改。可是將代碼稍加改動:
我們發(fā)現(xiàn),父子進程,輸出地址是一致的,但是變量內(nèi)容不一樣!能得出如下結(jié)論
OS必須負責(zé)將 虛擬地址 轉(zhuǎn)化成 物理地址 。
地址:內(nèi)存區(qū)域的編號
-----進程的虛擬地址空間—內(nèi)存描述符----mm_struct
操作系統(tǒng)通過mm_struct這個結(jié)構(gòu)體給進程描述了一個虛擬的地址
如何描述:
mm_struct{
ulong size;
ulong code_start;
ulong code_end;
ulong data_start;
ulong data_end;
}
為什么要使用虛擬地址空間虛擬地址空間+頁表
通過頁表進行映射,頁表可以進行標記,當(dāng)前地址是可讀還是可寫
提高內(nèi)存利用率
對內(nèi)存訪問進行控制
保證進程獨立性
虛擬內(nèi)存的方式
寫時拷貝技術(shù):提高子進程創(chuàng)建效率
進程O(1)調(diào)度方法
一個CPU擁有一個runqueue
普通優(yōu)先級:100~139(我們都是普通的優(yōu)先級,想想nice值的取值范圍,可與之對應(yīng)!實時優(yōu)先級:0~99(不關(guān)心)活動隊列
時間片還沒有結(jié)束的所有進程都按照優(yōu)先級放在該隊列 nr_active: 總共有多少個運行狀態(tài)的進程
queue[140]: 一個元素就是一個進程隊列,相同優(yōu)先級的進程按照FIFO規(guī)則進行排隊調(diào)度,所以,數(shù)組下 標就是優(yōu)先級!
從該結(jié)構(gòu)中,選擇一個最合適的進程,過程是怎么的呢?
bitmap[5]:一共140個優(yōu)先級,一共140個進程隊列,為了提高查找非空隊列的效率,就可以用5*32個 比特位表示隊列是否為空,這樣,便可以大大提高查找效率
過期隊列
active指針和expired指針
active指針永遠指向活動隊列
expired指針永遠指向過期隊列
可是活動隊列上的進程會越來越少,過期隊列上的進程會越來越多,因為進程時間片到期時一直都存在 的。
沒關(guān)系,在合適的時候,只要能夠交換active指針和expired指針的內(nèi)容,就相當(dāng)于有具有了一批新的活 動進程!
在系統(tǒng)當(dāng)中查找一個最合適調(diào)度的進程的時間復(fù)雜度是一個常數(shù),不隨著進程增多而導(dǎo)致時間成本增 加,我們稱之為進程調(diào)度O(1)算法
總結(jié)
以上是生活随笔為你收集整理的linux系统编程之进程概念(操作系统---管理,进程创建,进程状态,进程优先级, 环境变量,程序地址空间,进程O(1)调度方法)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 熊猫基地免费开放日
- 下一篇: Linux系统编程之进程控制(进程创建,