程序员不得不学的操作系统知识(二)
進程
進程的組成
進程是操作系統中分配資源的最小單位。進程由 3 個部分組成,分別是程序代碼、數據集、棧和進程控制塊(PCB)。
各自的作用如下:
程序代碼:描述了進程需要完成的功能。
數據集、棧:程序在執行時所需要的數據和工作區。
進程控制塊:包含進程的描述信息和控制信息,它是進程存在的唯一標識。
PCB:用來描述和控制進程運行的通用數據結構,是進程能夠獨立運行的基本單位。(常駐內存,存在系統專門開放的PCB塊)
進程的狀態
進程通信
信號signal:通過向一個或多個進程發送異步事件信號來實現,如:SIGSTOP、SIGKILL等信號。
管道pipe:在兩個進程之間,可以建立一個通道,一個進程向通道寫入字節流,另一個進程從管道讀取字節流。管道是同步的,當進程嘗試從空管道讀取數據時,該進程會被阻塞,直到有可用數據為止。如linux的 | 管線
共享內存:通過共享內存進行進程間通信,一個進程所作的修改對另一個進程可見。
先入先出隊列FIFO:也稱命名管道,具有支持文件和獨特 API ,命名管道在文件系統中作為設備的專用文件存在。而非命名管道在結束后緩沖區會被系統回收。
消息隊列:描述內核尋址空間內的內部鏈接列表。可以按幾種不同的方式將消息按順序發送到隊列并從隊列中檢索消息。每個消息隊列由 IPC 標識符唯一標識。
套接字Socket:提供端到端的雙向通信,可有TCP、UDP的支持。
進程同步
臨界資源:指的是一些雖作為共享資源卻又無法同時被多個進程或線程共同訪問的共享資源。為了對臨界資源進行有效的約束,就提出了進程間同步的四個原則
-
空閑讓進:資源無占用,允許使用
-
忙則等待:資源被占用,請求進程等待
-
有限等待:保證有限等待時間能夠使用資源,避免其它等待的進程僵死
-
讓權等待:等待時,進程需讓出CPU,也就是進程由執行狀態變為阻塞狀態,這也是保證CPU可以高效使用的前提
死鎖
死鎖定義:如果一組進程中的每個進程都在等待一個事件,而這個事件只能由該組中的另一個進程觸發,這種情況會導致死鎖。
死鎖的條件:
處理死鎖策略:
- 破壞互斥條件
- 破壞保持等待條件
- 破壞不可搶占條件
- 破壞循環等待條件
兩階段加鎖
一種解決方式是使用 兩階段提交(two-phase locking)。顧名思義分為兩個階段,一階段是進程嘗試一次鎖定它需要的所有記錄。如果成功后,才會開始第二階段,第二階段是執行更新并釋放鎖。第一階段并不做真正有意義的工作。
如果在第一階段某個進程所需要的記錄已經被加鎖,那么該進程會釋放所有鎖定的記錄并重新開始第一階段。從某種意義上來說,這種方法類似于預先請求所有必需的資源或者是在進行一些不可逆的操作之前請求所有的資源。
通信死鎖
進程 A 給進程 B 發了一條消息,然后進程 A 阻塞直到進程 B 返回響應。假設請求消息丟失了,那么進程 A 在一直等著回復,進程 B 也會阻塞等待請求消息到來,這時候就產生死鎖。
解決方法:超時重傳
**進程間同步的方法:**消息隊列、共享存儲、信號量。會在后邊的文章中詳細介紹這些進程間同步的方法
fork進程
-
fork系統調用是用于創建進程的
-
對于虛擬空間地址來說,子進程會拷貝父進程的虛擬地址空間。所以,fork后子進程的用戶區與父進程的用戶區相同,也會拷貝內核區內容,僅僅是進程的 pid不同。
-
在父進程中返回子進程的ID,在子進程中返回0。所以可以通過fork 的返回值來區分父進程與子進程
-
fork系統調用無參數
運用了讀時共享、寫時拷貝的原則,fork后,父子進程共享父進程的地址空間(只讀),在父進程或者子進程進行寫指令時,子進程才會復制一份地址空間,從而使得虛擬地址空間獨立,在自己的地址空間進行寫操作。也就是說,資源的復制是在需要寫入時才會進行,在此之前,只會以只讀方式進行共享。
進程類型
前臺進程:具有終端,可以和用戶進行交互的進程
后臺進程:不與用戶進行交互,優先級比前臺進程低
守護進程:特殊的后臺進程
孤兒進程:父進程退出后,子進程即成為孤兒進程,將由**init進程(pid為1)**收養
僵尸進程:子進程的進程描述符在子進程退出后不會釋放,只有當父進程調用**wait()、waitpid()**獲取子進程信息才釋放
線程
線程是操作系統進行運行調度的最小單位,線程除了擁有自己的棧、程序計數器等資源外,共享進程的資源。
通信,對于進程來說是進程間的通信(IPC),而對于線程,它是通過讀寫同一個進程的數據進行通信。
線程同步
互斥量
- 本質上是資源排他性使用,效果相當于原子性。擁有兩種狀態:加鎖和解鎖。(會帶來相關損耗,阻塞鎖)
- 自旋鎖:等待獲取資源的時候CPU不會釋放,優點:如果線程占用鎖時間不長,就能避免上下文切換代價;缺點:耗費CPU時間
- 讀寫鎖:讀不進行加鎖,寫的時候進行加鎖,對于多讀少寫的情況,性能能有很好的提升
信號量:表示同時允許訪問資源的最大線程數量,它是一個全局變量。(Java的semaphore)
條件變量:利用線程間共享的全局變量進行同步的一種機制,主要包括兩個動作:一個線程等待某個條件為真,而將自己掛起;另一個線程設置條件為真,并通知等待的線程繼續。條件變量與互斥量一起使用時,允許線程以無競爭的方式等待特定的條件發生。
- 基本動作:wait、signal、notify
調度算法
-
調度算法的目標:
-
先來先服務:按照FIFO的原則,將作業加入到就緒隊列中,按照順序調度作業。
-
最短作業優先:按照線程作業的CPU時間片,優先調度所需最短CPU時間片的作業。
-
最短剩余時間:最短作業優先的搶占式版本,總是調度剩余運行時間最短的作業。
-
輪詢調度:每個作業都會被分配一個CPU時間片,在這個時間片內允許進程運行。如果時間片結束時進程還在運行的話,則搶占一個 CPU 并將其分配給另一個進程。
-
優先級調度:按照作業優先級進行調度。
-
多級反饋隊列:設置多級隊列,設置不同優先級,并且分配不同的時間片。
POSIX線程
即線程標準。
| pthread_create | 創建一個新線程 |
| pthread_exit | 結束調用的線程 |
| pthread_join | 等待一個特定的線程退出 |
| pthread_yield | 釋放CPU來運行另外一個線程 |
| pthread_attr_init | 創建并初始化一個線程的屬性結構 |
| pthread_attr_destory | 刪除一個線程的屬性結構 |
線程實現
在用戶空間實現線程:
內核并不知道線程的存在,以進程為單位分配CPU時間片,每個進程要有專用的線程表。
優點:允許每個進程有自己定制的調度算法、調度效率比內核調用高(無需陷入內核,即上下文切換,無需刷新內存高速緩存)
缺點:會因為阻塞調用/缺頁中斷阻塞整個進程直到完成
在內核空間實現線程
內核中會有用來記錄系統中所有線程的線程表,當進行系統調度的時候,會通過對線程表的更新進行調度。線程表擁有每個線程的寄存器、狀態和其他信息。
優點:不會因某個線程阻塞而導致進程阻塞
缺點:系統調用代價大,上下文切換開銷大,以及需要切換系統狀態
混合實現:將用戶級線程與某些或者全部內核線程多路復用起來。編程人員可以自由控制用戶線程和內核線程的數量,具有很大的靈活度。內核只識別內核級線程,并對其進行調度。其中一些內核級線程會被多個用戶級線程多路復用。
了解更多文章,🙋?♂?關注公眾號:學編程的文若
總結
以上是生活随笔為你收集整理的程序员不得不学的操作系统知识(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle trim没用,Oracle
- 下一篇: 程序员不得不学的操作系统知识(一)