一、什么是進程
二、進程的創建
三、進程的狀態
四、僵尸進程
五、孤兒進程
六、進程的優先級 以及 并發/并行
七、進程的切換
一、什么是進程?
什么是進程呢(一)?
官方話來說:進程是一個執行實例、正在執行的程序、是系統資源分配的基本單位
按課本官方話可能有一點點的不好理解
通俗的講:當你電腦上的程序,比如qq 你雙擊運行起來,此時他啟動了,那么他現在就是一個進程
再深講:當你的代碼被編譯鏈接成為一個可執行程序,這個可執行程序本質上是一個文件,是被放到磁盤里的,當雙擊運行,這個程序會被加載到內存,也就是大家所說的內存條,當加載到內存,
此時程序的代碼會一條一條的被cpu執行,此時這個程序不再叫程序而是叫做進程了
在Linux下通過指令ps aux 可以查看當前正在運行的進程
還可以通過系統目錄查看當前進程
什么是進程呢(二)?
看過我前面文章里的操作系統的話,我說到了操作系統的管理
操作系統要對進程進行管理,如何管理的呢?
進程再往深講:進程就是一個結構體,這個結構體名字叫做PCB控制塊
PCB控制塊里面存放了進程屬性的集合
PCB在Linux下就是 task_struct 名字的結構體
所謂的進程記載到內存,實際上就是PCB結構體加載到了內存
在這個PCB結構體內存放了進程的各種屬性,比如進程狀態、優先級、標識符、父進程標識符、
程序計數器、內存指針、上下文數據、其他信息等
這些PCB結構體會被以雙向鏈表的形式被操作系統進行管理
通過這樣,操作系統可以訪問所有的PCB,也就等于訪問到了所有的進程,對進程的管理也就轉換為了對PCB結構體的管理
當一個程序被啟動變為進程,進程的代碼和數據會加載到內存,然后操作系統會形成相應的PCB,
并把PCB放入鏈表中,而一個進程的退出,也就是從鏈表中刪除這個節點,然后對代碼和數據進行釋放
總結就是:操作系統對進程的管理實際上就變成了對鏈表的增刪改查、不管是對進程的管理,還是文件內存等,本質都是對一種數據結構的增刪改查
二、進程的創建
通過系統調用可以在一個進程中再創建一個子進程
fork函數創建子進程
運行結果是每次循環會打印兩行數據,第一行是該進程的Pid和PPid
第二行是子進程的Pid和PPid
我們可以發現這兩個進程是父子關系,子進程的PPid=該進程的Pid
每次出現一個進程,操作系統就會為其創建一個PCB,fork函數創建的進程也不例外
為什么子進程也執行跟父進程相同的代碼呢?
原因解釋:子進程被創建后會共享父進程的代碼和數據,但是采用的是寫時拷貝
什么意思呢?子進程會執行和父進程相同的代碼,但是如果修改父進程的數據,他就不會共享該數據的地址了,而是為自己開辟一個空間放這個數據,這樣的設計減少來了內存的浪費,只有在需要的時候才分配內存
注意點??:fork函數是返回兩個返回值的,因為在fork函數內部就已經創建了子進程,已經分配了PCB,并且放入了cpu的調度隊列,在fork函數內的return返回值前已經是兩個進程在跑了,所以父子進程的執行順序是不確定的,取決于操作系統的調度方式
如何讓子進程執行自己的代碼呢?
使用if進行分流即可,因為有兩個返回值,而兩個返回值明確區分了,=0代表是子進程,>0代表是父進程,通過if區別返回值,即可讓父子進程執行不同的代碼
如果返回值<0 代表創建進程失敗了,可能是因為沒有內存了,也可能進程創建數量達到了上限
三、進程的狀態
一個進程從創建到銷毀,會經歷很多不同的狀態
我這里直接總結了一下:
創建/新建狀態:
如果一個進程在被創建的時候,比如分配PCB,比如fork函數內,那么這個進程就處于新建狀態
什么是新建狀態呢?就是還沒有被執行
就緒狀態:
當分配完PCB并且放到了cpu的調度隊列,等待被cpu執行自己的代碼,此時就進入了就緒狀態
也就是等待被執行
運行狀態:
當真正被cpu調度的時候,開始執行自己的代碼,就進入了運行狀態
阻塞狀態:
當在程序運行中,因為某種原因阻塞,比如等待鍵盤輸入數據,此時操作系統識別到后,會把進程放入該等待外設設備的等待隊列中,然后進程進入阻塞狀態,直到鍵盤輸入數據,操作系統才會重新將進程重新放入運行隊列里去等待執行
阻塞掛起狀態:
什么是阻塞掛起狀態呢?當內存中由于進程數量過多,內存不夠的時候,操作系統會選擇將一部分進程的代碼和數據放入磁盤中,只在內存中保留PCB控制塊,這些代碼和數據會被放到磁盤中的swap分區中,這個分區的大小一般是內存的1.5倍或者2倍,當需要的時候就把代碼和數據再交換會內存進行調度,這就是阻塞掛起狀態
個人超詳細總結:
四、僵尸進程
還有一種狀態叫做僵尸狀態 - Z
當一個進程變成僵尸進程就陷入了僵尸狀態
僵尸進程:父子進程中,子進程退出,但是父進程沒有回收子進程的資源,導致子進程的PCB控制塊一直保留在內存,雖然子進程的代碼和數據已經釋放,但是PCB控制塊沒有釋放,導致內存泄露的問題,此時子進程變成僵尸進程,使用kill命令也無法殺死
為什么會有僵尸進程呢?
因為子進程的PCB控制塊內有返回值信息和狀態信息,還有自己的pid
這些信息可能對于父進程是有效的,所以系統不會主動釋放,而是等待父進程來回收這些資源才會
釋放
僵尸進程的危害?
如果一個父進程創建了很多子進程都不回收,造成嚴重的內存泄露問題,可用資源越來越少
如何解決僵尸進程呢?
父進程調用系統調用來進行回收,或者通過捕捉信號的方式(涉及到信號的知識)
如果已經發生僵尸進程,需要殺死父進程來讓僵尸進程變為孤兒進程被系統自動領養回收
五、孤兒進程
前面提到了僵尸進程,那什么是孤兒進程呢?跟僵尸進程相反
如果父進程早于子進程退出了,此時子進程沒有父親了,就變成了孤兒進程
孤兒進程會被1號進程也就是系統領養,由系統管理回收
孤兒進程最終會被釋放,而僵尸進程危害較大
六、進程的優先級 以及 并發/并行
簡短總結:
七、進程的切換
簡短總結: