【操作系統】第七章進程與線程

以下是操作系統的各部分知識點的目錄:
第一章:操作系統的概述
https://blog.csdn.net/weixin_44751294/article/details/104172847
第二章:啓動、中斷、異常和系統調用
https://blog.csdn.net/weixin_44751294/article/details/104172778
第三章:續內存分配
https://blog.csdn.net/weixin_44751294/article/details/104183639
第四章:非連續內容分配
https://blog.csdn.net/weixin_44751294/article/details/104190197
第五章:虛存技術
https://blog.csdn.net/weixin_44751294/article/details/104196572
第六章:頁面置換算法
https://blog.csdn.net/weixin_44751294/article/details/104204687
第七章:進程與線程
https://blog.csdn.net/weixin_44751294/article/details/104228830
第八章:處理機調度
https://blog.csdn.net/weixin_44751294/article/details/104229011
第九章:同步互斥問題
https://blog.csdn.net/weixin_44751294/article/details/104235209
第十章:信號量與管程
https://blog.csdn.net/weixin_44751294/article/details/104248160
第十一章:死鎖與進程通信
https://blog.csdn.net/weixin_44751294/article/details/104259732
第十二章:文件系統
https://blog.csdn.net/weixin_44751294/article/details/104268956

進程管理的主要內容
1、進程(Process)描述
2、進程狀態(State)
3、線程(THREAD)
4、進程間通信(INTER-PROCESS COMMUNICATION)
5、進程互斥與同步
6、死鎖(DEADLOCK)

7.1進程的定義

在某種程度上, 可以將應用程序看成是一個進程,其將會消耗耕種各樣的計算機資源。

定義:
一個具有一定獨立功能的程序在一個數據集合上的一次動態執行過程。

只有當操作系統把執行程序調入到我們的內存之後,讓這個程序可以執行起來。(能夠讓通過cpu對這個程序執行一條條的指令,讀取數據完成一定的功能)。也就是靜態的執行程序,通過cpu變成一個動態的執行過程,而這個動態的執行過程就是進程。
整個的功能是由程序的代碼決定的。

7.2進程的組成

1、一個進程應該包括

  • 程序的代碼
  • 程序處理的數據
  • 程序計數器中的值,指示下一條將運行的指令
  • 一組通用的寄存器的當前值,堆,棧
  • 一組系統資源(如打開的文件)

總之,進程包含了正在運行的一個程序的所以狀態信息。

2、進程與程序的聯繫

  • 程序是產生進程的基礎
    程序是靜態的代碼,代碼限制了進程完成是什麼樣的功能
  • 程序的每次運行構成不同的進程
    程序多次運行過程中輸入的數據不一樣,產生的結果是不一樣的,所以構成了不一樣的進程
  • 進程是程序功能的體現
    儘管輸出可能不同,但是這個程序的功能是一樣的
  • 通過多次執行,一個程序可對應多個進程;通過調用關係,一個進程可包括多個程序。
    進程和程序之間是一個多對多的關係。

3、進程與程序的區別

  • 進程是動態的,程序是靜態的;程序是有序代碼的集合;進程是程序的執行,進程有核心態/用戶態。
  • 進程是暫時的,程序是永久的;進程是一個狀態變化的過程,程序可長久保存。
  • 進程與程序的組成不同;進程的組成包括程序、數據和進程控制塊(既進程狀態信息)

一個很有趣進程與cpu的類比:
在這裏插入圖片描述

  • cpu在工作中會存在切換處理不同程序的

7.3進程的特點

  • 動態性:可動態地創建,結束進程;
  • 併發性:進程間可以被獨立調度並佔有處理機運行;(併發與並行的區別,前者是可以爲1個cpu,後者必須要多個cpu)
  • 獨立性:不同進程的工作不互相影響,也就是進程不會破壞代碼數據的正常執行。(頁表的支持)
  • 制約性:因訪問共享數據/資源或進程間同步而產生制約
    在這裏插入圖片描述
    a–體現了動態性 / b–體現了獨立性 / c–體現了制約性

描述進程的數據結構:進程控制塊(Process Control Block,PCB)
操作系統爲每一個進程都維護了一個PCB,用來保存與該進程有關的各種狀態信息和需要資源的情況等等。

7.4進程控制結構

1、進程控制塊:操作系統管理控制進程運行所用的信息集合。

  • 操作系統用PCB來描述進程的基本情況以及運行變化的過程,PCB是進程存在的唯一標誌,如果進程消失了那麼其對應的PCB也會消失,是一一對應的關係。

2、使用進程控制塊

  • 進程的創建:爲該進程生產一個PCB;
  • 進程的終止:回收它的PCB;
  • 進程的組織管理:通過對PCB的組織管理來實現;

問題:PCB具體包含什麼信息?如何組織的?進程的狀態轉換…?

3、PCB包含的信息
1)進程標識信息。
如本進程的標識(進程號,執行的次數…),本進程的產生者標識(父進程標識);用戶標識。
2)處理機狀態信息保存區
保存進程的運行現場信息:

  • 用戶可見寄存器:用戶程序可以使用的數據,地址等寄存器。
  • 控制和狀態寄存器:如程序計數器(PC),程序狀態字(PSW)
  • 棧指針:過程調用/系統調用/中斷處理和返回時需要用到它。找到當前運行的位置。

3)進程控制信息
操作系統需要對這個進程進行管理和控制調度和

  • 調度和狀態信息:用於操作系統調度進程並佔用處理機使用。
  • 進程間通信信息:爲支持進程間與通信相關的各種標識,信號,信件等。這些信息存在接受方的進程控制塊中
  • 存儲管理信息:包含有指向本進程映射存儲空間的數據結構。
  • 進程所用資源:說明有進程打開、使用的系統資源,如打開的文件等。
  • 有關數據結構連接信息:進程可以連接到一個進程隊列中,或連接到相關的其他進程的PCB

4、PCB的組織方式

  • 鏈表:同一狀態的進程其PCB稱一鏈表,多個狀態對應多個不同的鏈表。各個狀態的進程形成不同的鏈表:就緒鏈表,阻塞鏈表。
  • 索引表:同一個狀態的進程歸入一個index表(由index指向PCB),多個狀態對應多個不同的index表。各個狀態的進行形成不同的索引表:就緒索引表、阻塞索引表

一般來說會採取鏈表,因爲進程的控制是動態的插入和刪除的,所以鏈表組織方式比較方便,而索引開銷比較大。當然如果一開始就固定住了進程的數目,索引也不失爲一個選擇。
在這裏插入圖片描述
以上是圍繞進程靜態部分說明,組成,特點等等。
一下是圍繞進程動態的狀態特點說明,有3個方面的內容:

  • 進程的生命週期管理
  • 進程狀態變化模型
  • 進程掛起模型

7.5進程的生命期管理

進程的生命是指進程的創建到結束這麼一整個的生命期。
進程的生命期管理有以下幾個時期:

  • 進程創建
  • 進程運行:正在佔用cpu,執行這個進程
  • 進程等待:由於某種特殊原因需要等待
  • 進程喚醒:當等待的條件滿足,需要喚醒
  • 進程結束

1、進程創建
引起進程創建的3個主要事件:
1)系統初始化時
2)用戶請求創建一個新進程
3)正在運行的進程執行了創建進程的系統調用
但是創建了新的進程不一定可以執行。

2、進程運行
內核選擇一個就緒的進程,讓它佔用處理機並執行
就緒態----->執行態
在這裏插入圖片描述
其中涉及兩個問題:
1)爲何選擇?
2)如何選擇?(涉及調度算法)

3、進程等待
在以下情況下,進程等待(阻塞):

  1. 請求並等待系統服務,無法馬上完成
    2)啓動某種操作,無法馬上完成
    3)需要的數據沒有到達
    在這裏插入圖片描述
    ps:進程等待事件的發起是有自己發起的。因爲進程只能自己阻塞自己,因爲只有進程自身才能知道何時需要等待某種事件的發生。

4、進程喚醒
喚醒進程的原因:
1) 被阻塞進程需要的資源可被滿足
2) 被阻塞進程等待的事件到達
3) 將該進程的PCB插入到就緒隊列
在這裏插入圖片描述
ps:進程只能被別的進程或者操作系統喚醒

5、進程結束
在以下四種情況下,進程結束
1)正常退出(自願的)
2)錯誤退出(自願的)
3)致命錯誤(操作系統強制性的)
4)被其他進程所殺(強制性的)
在這裏插入圖片描述

7.6進程狀態變化模型

1、進程的三種基本狀態
進程在生命結束前處於且僅處於三種基本狀態之一,不同系統設置的進程狀態數目不同。
1)運行狀態(Running):當一個進程正在處理機上運行時。
2)就緒狀態(Ready):一個進程獲得了除處理機之外的一切所需資源。一旦得到處理機即可運行。
3)等待狀態(又稱阻塞狀態Blocked):一個進程正在等待某一事件而暫停運行時。如等待某資源,等待輸入/輸出完成。

2、三狀態變化圖:
在這裏插入圖片描述
進程其他的基本狀態:

  • 創建狀態(New):一個進程正在被創建,還沒被轉到就緒狀態之前的狀態。
  • 結束狀態(Exit):一個進程正在從系統中消失時的狀態,這是因爲進程結束或由於其他原因所導致。

3、五狀態變化圖:
在這裏插入圖片描述
就緒態的出現是由於調度機制的存在。

4、可能的狀態變化如下:

  • NULL->New: 一個新進程被產生出來執行一個程序。
  • New->Ready: 當進程被創建完成並初始化後,一切就緒準備運行時,變爲就緒狀態。(不會持續很久,也就只是一個PCB的初始化。)
  • Ready->Running :處於就緒狀態的進程被進程調度程序選中後,就分配到處理機上來運行。
  • Running->Exit :當進程表示它已經完成或出現錯誤,當前運行進程會有操作系統作結束處理。
  • Running->Ready :處於運行狀態的進程在其運行過程中,由於分配給它的處理機時間片用完而讓出處理機。(操作系統完成)
  • Runing->Blocked :當進程請求某樣東西切必須等待時。(例如等待一個定時器的到達,讀寫文件,因爲過程比較慢)
  • Blocked->Ready :當進程要等待某事件到來時,它從阻塞狀態變到就緒狀態。(同樣由操縱系統完成)

7.7進程的掛起

進程掛起和進程阻塞的不一樣的。
進程在掛起狀態意味着進程沒有佔有內存空間。處於掛起狀態的進程影像在磁盤上。

1、掛起狀態
1)阻塞掛起狀態(Blocked-suspend):進程在外存並等待某事件的出現;
2)就緒掛起狀態(Ready-suspend):進程在外存,但只要進入內存,即可運行。

2、與掛起中相關的狀態轉換
掛起(Suspend):把一個進程從內存轉到外存;可能有以下幾種情況:
1)阻塞到阻塞掛起:沒有進程處於就緒狀態或就緒進程要求更多內存資源時,會進行這種轉換,以提高新進程或運行就緒進程;
2)就緒到就緒掛起:當有高優先級阻塞(系統認爲會很快就緒的)進程和低優先級就緒進程時,系統會選擇掛起低優先級就緒進程;
3)運行到就緒掛起:對搶先式分時系統,當有高優先級阻塞掛起進程因事件出現(空間不夠)而進入就緒掛起,系統可能會把運行進程轉到就緒掛起狀態。

  • 在外存時的狀態轉換:

阻塞掛起到就緒掛起:當有阻塞掛起進程相關事件出現時(也就是條件滿足),系統會把阻塞掛起進程轉換到就緒掛起進程。

  • 解掛/激活(Activate):把一個進程從外存轉到內存;可能有以下幾種情況:

1)就緒掛起到就緒:沒有就緒進程或掛起就緒進程優先級高於就緒進程時,會進行這種轉換。
2)阻塞掛起到阻塞:當一個進程釋放足夠內存時,系統會把一個高優先級阻塞掛起(系統認爲會很快出現所等待的事件)進程轉換爲阻塞進程。

問題:操作系統怎麼通過PCB的定義的進程狀態來管理PCB,幫助完成進程的調度過程?
在這裏插入圖片描述
以進程爲基本結構的os,選擇某一個進程變成某一種狀態都是有操作系統來完成的。最底層爲CPU調度程序(包括中斷處理等)。上面一層爲一組各式各樣的進程。

3、狀態隊列
狀態隊列是操作系統管理進程的一個很重要的數據結構
1)由操作系統來維護一組隊列,用來表示系統當中所以進程的當前狀態;
2)不同的狀態分別用不同的隊列來表示(就緒隊列,各種類型的阻塞隊列);
3)每個進程的PCB都根據它的狀態加入到相應的隊列當中,當一個進程的狀態發生變化時,它的PCB從一個狀態隊列中脫離出來,加入到另外一個隊列。

4、狀態表示方法
在這裏插入圖片描述
要注意,如果事件1只能滿足一個進程,那麼只能把這一個進程從阻塞態變成就緒態。如果事件1產生之後,所以等待事件1的進程都等到滿足,那麼這些進程都會掛到就緒隊列裏面去。

線程管理:
很久之前,操作系統一直以進程作爲獨立運行的基本單位,直到80年代中期,人們有提出了更小獨立運行的基本單位—線程。
1)爲什麼使用線程?
2)什麼是線程
3)線程的實現
4)多線程編程接口舉例

7.8爲什麼使用線程

例子:
在這裏插入圖片描述
1、單進程的實現方法
在這裏插入圖片描述
可能出現的問題:
1)播放出來的聲音能否連續?
2)各個函數之間不是併發執行,影響資源的使用效率。

2、多進程的實現方法
在這裏插入圖片描述
可能出現的問題:
1)進程之前如何通信,共享數據?
2)維護進程的系統開銷比較大:
創建進程時,分配資源,建立PCB;撤銷進程時,回收資源,撤銷PCB;進程切換時,保存當前進程的狀態信息。

根據以上問題,提出一個新的實體,滿足一下特性:
1)實體之間可以併發地執行;
2)實體之間共享相同的地址空間;

這個實體就是:線程(Thread)

7.9什麼是線程

1、定義:進程當中的一條執行流程

2、從兩個方面來重新理解進程
1)從資源組合的角度:
進程把一組相關的資源組合起來,構成了一個資源平臺(環境),包括地址空間(代碼段,數據段)、打開的文件等各種資源;
2)從運行的角度:
代碼在這個資源平臺上的一條執行流程(線程)。
在這裏插入圖片描述
ps:進程中的堆,代碼段,數據段是線程所共享的內容。而各自又有獨特的內容,比如所堆棧,程序計數器,寄存器(不同的執行留和控制流)。所以其有獨立擁有的部分,也有公有的部分。

3、線程 = 進程 - 共享資源
線程的優點:
1)一個進程中可以同時存在多個線程
2)各個線程之間可以併發地執行
3)各個線程之間可以共享地址空間和文件等資源

線程的缺點:
一個線程奔潰,會導致其所屬進程的所以線程奔潰,安全沒有一定的保障。

4、不同操作系統對線程的支持
在這裏插入圖片描述
5、線程所需的資源
在這裏插入圖片描述
6、線程與進程的比較
1)進程是資源分配單位,線程是CPU調度;
2)進程擁有一個完整的資源平臺,而線程只獨享必不可少的資源,如寄存器和棧;
3)線程同樣具有就緒、阻塞和執行三種基本狀態,同樣具有狀態之間的轉換關係;
4)線程能減少併發執行的時間和空間開銷;

  • 線程的創建時間比進程短;
  • 線程的終止時間比進程短;
  • 同一進程內的線程切換時間比進程短;
  • 由於同一進程的各線程間共享內存和文件資源,可直接進行不通過內核的通信。

(切換進程的時候,需要把頁表也切換掉,切換頁表的開銷比較大,因爲硬件的信息無效,需要重新加載)

7.10線程的實現

主要有三種線程的實現方式:
1)用戶線程:在用戶空間實現;
2)內核線程:在內核中實現;
3)輕量級進程:在內核彙總實現,支持用戶線程

用戶線程:操作系統看不到的線程稱爲用戶線程
內核線程:操作系統管理起來(能夠看見)的線程稱爲內核線程

1、用戶線程與內核線程的對應關係
1)多對一
在這裏插入圖片描述
2)一對一
在這裏插入圖片描述
3)多對多
在這裏插入圖片描述
2、用戶進程
在這裏插入圖片描述
線程控制塊(TCB)是在庫裏面實現的,對於操作系統而言,其看不見TCB,只能看見進程的信息,但是進程裏面的線程信息,是有線程管理的庫來實現的。
在用戶空間實現的線程機制,它不依賴與操作系統的內核,由一組用戶級的線程庫函數來完成線程的管理,包括進程的創建,終止,同步和調度等。

  • 由於用戶線程的維護由相應進程來完成(通過線程庫函數),不需要操作系統內核瞭解用戶線程的存在,可用於不支持線程技術的多進程操作系統;
  • 每個進程都需要它自己私有的線程控制塊(TCB)列表,用來跟蹤記錄它的各個線程的狀態信息(PC,棧指針,寄存器),TCB由線程庫函數來維護;
  • 用戶線程的切換也是由線程庫函數來完成,無需用戶態/核心態切換,所以速度特別快;
  • 允許每個進程擁有自定義的線程調度算法。

否則如果進程被操作系統調度爲阻塞態,則其下的所有線程都無法允許。

用戶線程的缺點:
1)阻塞性的系統調用如何實現?如果一個線程發起系統調用而阻塞,則整個進程在等待。因爲操作系統只能看見進程,所以這個進程阻塞,旗下所以的線程都會阻塞。
2)當一個線程開始執行後,除非它主動地交出CPU的使用權,否則它所在的進程當中的其他線程將無法運行。
3)由於時間片分配給進程,故與其他進程比,在多線程執行時,每個線程得到的時間片較少,執行會較慢。

3、內核線程
(操作系統看得見,TCB是放在內核裏面的)
在這裏插入圖片描述
內核線程是指在操作系統的內核當中實現的一種線程機制,由操作系統的內核來完成線程的創建,終止和管理。

  • 在支持內核線程的操作系統中,由內核來維護進程和線程的上下文信息(PCB和TCB);
  • 線程的創建,終止和切換都是通過系統調用/內核函數的方式來進行,由內核來完成,因此係統開銷較大;
  • 在一個進程當中,如果某個內核線程發起系統調用而被阻塞,並不影響其他內核線程的運行;
  • 時間片分配給線程,多線程的進程獲得更多的cpu時間;
  • Windows NT和Windows 200/XP支持內核線程

4、輕量級進程(LightWeight Process)
它是內核支持的用戶線程,一個進程可有一個或多個輕量級進程,每個輕量級進程有一個單獨的內核線程來支持,(Solaris/Linux)
在這裏插入圖片描述

7.11上下文切換

1、定義:停止當前運行的進程(從運行狀態改變成其他狀態)並且調度其他進程(轉變成運行狀態的)的過程,稱爲進程的上下文切換(Compress)

  • 必須在切換之前存儲許多部分的進程上下文
  • 必須能夠在之後恢復他們,所以進程不能顯示它曾經被暫停過
  • 必須快速(上下文準換是非常頻繁的)

進程的上下文切換所具體切換的進程所用到的寄存器,使用要關注cpu有哪些寄存器(PC程序計數器,SP堆棧指針)。而在做進程切換的時候,需要將這新信息保存到進程控制塊的某一個地方上。

2、切換的過程
在這裏插入圖片描述
所用的信息都是和硬件緊密相連的,所用一般是使用匯編代碼來完成編寫。

操作系統爲活躍進程準備了進程控制塊(PCB)
操作系統將進程控制塊(PCB)放置在一個合適的隊列裏

  • 就緒隊列
  • 等待I/O隊列(每個設備的隊列)
  • 殭屍隊列
    在這裏插入圖片描述

7.12進程控制—創建進程

window系統下:
在這裏插入圖片描述
linux系統下:
在這裏插入圖片描述
fork()創建一個繼承的子進程

  • 複製父進程的所有變量和內存
  • 複製父進程的所以CPU寄存器(有一個寄存器除外)

fork()的返回值

  • 子進程的fork()返回0
  • 父進程的fork()返回子進程標識符
  • fork()返回值可方便後續使用,子進程可使用getpid()獲取PID

父子進程的主要區別----childPID不一樣:
在這裏插入圖片描述

7.13進程控制—加載和執行過程

系統調用exec()加載程序取代當前運行的進程
在這裏插入圖片描述
其中:
exec是準備執行一個新的程序,所以當成功的執行了exec之後,後面的printf函數是不會執行到的。
wait(pid); wait返回了,表示子進程就結束了。

當執行exec的時候,代碼數據都複製了一份,但是PID沒有變化。但是執行的代碼改變了,也就是另外程序的執行過程,如下所示。
在這裏插入圖片描述
執行exec之後,程序的整個控制流會放生完全的變化

在這裏插入圖片描述
1)exec()調用允許一個進程“加載”一個不同的程序並且在main開始執行(事實上_start,系統調用)
2)它允許1一個進程指定參數的數量(argc)和它字符串參數數組(argv)
3)代碼段,數據段,stack(棧)&heap(堆)都會被覆蓋

fork()的簡單實現

  • 對子進程分配內存
  • 複製父進程的內存和CPU寄存器到子進程裏

在99%的情況裏,我們在調用fork()之後調用exec()

  • 在fork()操作中內存複製是沒有作業的
  • 子進程將可能關閉打開的文件和鏈接

對於此情況需要一個優化:
vfork(),vfork只是複製了一小部分的進程的內容,絕大多數的內容都沒有被複制。但是這會使系統調用變成兩個fork,增加了編程人員的開銷。

另一個優化:
通過虛存管理科員實現一個高效的fork實現機制。也就是(Copy on Write,COW)技術,就是寫的時候再進行復制。
當父進程創建子進程的時候,如果採用COW技術時,我們在做實際的子進程地址空間複製的時候並沒有真是的複製,只是複製了父進程所需要的元數據—頁表等等,實現按需寫的情況來複制不同的頁。

7.14進程控制—等待和終止進程

wait()系統調用是被父進程用來等待子進程的結束

  • 父進程先與子進程死亡—子進程爲孤兒進程
  • 子進程已經死亡,但父進程還沒來得及回收—子進程爲殭屍進程

狀態轉換圖:
在這裏插入圖片描述
ps:執行exec的時候,程序有可能會處於不同的狀態。
因爲在執行exec有兩個步驟,一個是加載執行程序,二個是運行執行程序。加載的時候,所需要的時間比較長,所以會處於阻塞狀態。

參考鏈接:https://www.bilibili.com/video/av6538245

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章