1. 程式人生 > >作業系統(四)同步互斥機制&管程&程序間通訊

作業系統(四)同步互斥機制&管程&程序間通訊

1.程序的併發執行

併發是所有問題產生的基礎,也是OS設計的基礎

併發:程序的執行是間斷性的,程序的相對執行速度不可預測

2.程序互斥:

由於各程序要求使用共享資源(變數、檔案),而這些資源需要排他性使用,各程序之間競爭使用這些資源

臨界資源:系統中某些資源一次只允許一個程序使用(也叫臨界資源、互斥資源、共享資源)

臨界區(互斥區):各個程序中對某個臨界資源(共享變數)試試操作的程式片段

記不記得OS的程序or執行緒通訊有這個!!

競爭條件:兩個或者多個程序讀寫某些共享資料時,最後的結果取決於程序執行的精確時序

3.臨界區的使用原則:

沒有程序在臨界區時,想進入臨界區的程序可進入

不允許兩個程序同時處於臨界區

臨界區執行的程序不得阻塞 其他程序進入臨界區

不得使用程序無限期等待進入臨界區

4.實現程序的方案:

(1)軟體方案:Dekker Peterson (程式設計技巧)

(2)硬體:遮蔽中斷 TSL(XCHG)指令

忙等待 不斷測試CPU,而不做其他事情(單處理器不推薦)

多處理器中自旋鎖 Spin lock

5.中斷遮蔽方法:

“開關中斷”指令

執行“關中斷”指令

   臨界區操作

執行“開中斷”指令

特點:

簡單,高效;

代價高,限制CPU併發能力(臨界區大小);

不適合於多處理器;

適合於作業系統本身,不適合用於程序

6.TSL指令:測試並加鎖 test and set lock

enter_region:

複製鎖到暫存器並將鎖置為1

判斷暫存器內是否是0

若不是0 進入enter_region

返回呼叫者,進入臨界區

leave_region:

鎖中置0

返回呼叫者

7.XCHG指令 交換指令

暫存器與鎖變數的內容交換

8.程序同步:

多個程序中發生的事件存在某種時序關係,需要互相合作,共同完成一項任務

具體的說,一個程序執行到某一個點時,要求另一個夥伴程序為他提供訊息,在未獲得訊息之前,該程序進入阻塞態,獲得訊息後被環形進入就緒態

9.生產者/消費者問題:(有界緩衝區問題)

問題描述:

一個或者多個生產者生產某種型別的資料放置在緩衝區中,有消費者從緩衝區中取資料,只能有一個生產者或消費者對緩衝區進行操作

要解決的問題:

當緩衝區已滿時,生產者不會繼續向其中新增資料;

當緩衝區為空時,消費者不會從中移走資料。

避免忙等待。睡眠與喚醒操作

程式碼部分看linux的那本培訓書吧

spooling技術中也可以認為,輸入程式和輸出程式是一對生產者、消費者

10.訊號量及PV操作(一種經典的程序同步機制)又是一個之前無數遍聽說過不知道的概念

訊號量:一種特殊的變數,用於程序間傳遞資訊的一個整數值 對訊號量實施的操作:初始化、P操作、V操作

P(s)

{

  s.count--;

  if(s.count<0)

  {

      該程序狀態置為阻塞狀態;將該程序插入相應的等待佇列s.queue的末尾;重新排程

  }

}

V(s)

{

  s.count++;

  if(s.count<=0)

  {

      喚醒相應等待佇列s.queue中等待的一個程序;改變其狀態為就緒態,並將其插入就緒佇列

  }

}

PV都是原子操作;

在訊號量上定義了三個操作:初始化(非負數)、p、v

最初提出的是二元訊號量,推廣到一般訊號量(計數訊號量)

11、PV操作解決程序間互斥問題的過程:

分析併發程序的關鍵活動,劃定臨界區

設定訊號量mutex,初值為1

在臨界區前實施P

在臨界區之後實施V

之前一直在想 為啥生產者/消費者這個這麼眼熟……好像是設計模式裡有吧
(空行的地方加 P(mutex) V(mutex)操作)

兩個P操作不能顛倒,會死鎖

兩個V操作可以顛倒,但是臨界區會擴大(雖然不會出錯)

12.訊號量解決讀者/寫者問題

問題描述:多個程序共享一個數據區,分為兩組:只讀的程序;只寫的程序

要求的條件:

允許多個讀者同時執行讀操作;不允許多個寫者同時操作;不允許讀者、寫者同時操作

(1)讀者優先

如果讀者執行:

無其他讀者、寫者,該讀者可以讀

若已經有寫者,但有其他讀者正在讀,則該讀者可以讀

若寫者正在寫,該讀者必須等

如果寫者執行:

無其他讀者、寫者,該寫者可以寫

若有讀者正在讀,該寫者等待

若有其他寫者正在寫,該寫者等待

第一個讀者需要做P(w)後續的可以不做P操作;最後一個讀者做V(w)

linux中的讀寫鎖:

應用場景:

如果每個執行實體對臨界區的訪問或者讀寫是寫共享變數,但他們不會讀+寫,讀寫鎖是最好的選擇

e.g.維護路由表ipx路由程式碼

13.管程:

提出原因:訊號量機制不足:程式編寫困難、易出錯

方案:在程式設計語言中引入一種高階維護機制

定義:

是一個特殊的模組;

有一個名字;

由關於共享資源的資料結構及在其上操作上的一組過程組成。

程序只能通過呼叫管程中的過程間接訪問管程中的資料結構

14.需要解決問題

(1)互斥:管程是互斥進入的 為了保證資料結構的資料完整性

管程的互斥由編譯器負責保證的,是一種語言機制

(2)同步:設定條件變數及等待喚醒操作以解決同步問題

可以讓一個程序或者執行緒在條件變數上等待(先釋放管程的管理權),也可以通過傳送訊號將等待在條件變數上的程序執行緒喚醒

15.應用管程遇到的問題:

當一個進入管程的程序執行等待操作時,它應當釋放管程的互斥權。當後面進入管程的程序執行喚醒操作時(例如P喚醒Q),管程中便存在兩個同時處於活動狀態的程序

解決方法:

P等待Q (Hoare)

Q等待P (MESA)

規定喚醒操作為管程中最後一個可執行的操作(Hansen 併發pascal)

16.HOARE管程:

17.管程的實現:

(1)直接構造 效率高

(2)間接構造 用某種已經實現的同步機制去構造

18.MESA管理:

提出由於Hoare管程的缺點:兩次額外的程序切換

P程序喚醒Q,P限制性

解決:signal->notify

當一個正在管程中的程序執行notify(x)時,它使得x條件佇列得到通知,發訊號的程序繼續執行

使用notify要注意的問題:

notify的結果:位於條件佇列頭的程序在將來合適的時候且當處理器可用時回覆執行

由於不能保證在它之前沒有其他程序進入管程,因而這個程序必須重新檢查條件 用while迴圈取代if語句

導致對條件變數至少多一次額外的檢測,且對等待程序在notify之後合適執行沒有任何限制

19.notify的改進:

給每個條件原語關聯一個監視計時器,無論是否被通知,一個等待時間超過的程序被設為就緒態

當改程序被排程執行,會再檢查相關條件,如果條件滿足則繼續執行

超時可以預防:當某些程序在產生相關訊號前失效

20.broadcast:使所有在該條件上等待的程序都被釋放並進入就緒佇列

當一個程序不知道有多少程序將被啟用時,這種方式是非常方便的

當一個程序不能準確判斷啟用哪個程序時,也可以使用廣播

21.hoare&mesa比較

M管程優於H管程之處在於M管程錯誤比較少

在M中,優於每個過程中在收到訊號後都重新檢查管程變數,並且由於使用了while結構,一個程序不正確的broadcast廣播或者發訊號notify不會導致收到訊號的程式出錯

收到訊號的程式將檢查相關的變數,如果期望的條件沒有滿足,它會重新繼續等待

22.pthread中的同步機制:

通過互斥量保護臨界區 (記不記得互斥量好像也是通訊的一種方式

通過條件變數解決同步問題(用的MESA管程)

pthread_cond_wait三個主要動作:

(1)解鎖

(2)等待:

當收到一個解除等待的訊號(pthread_cond_signal 或者 pthread_cond_broad_cast)之後,pthread_cond_wait馬上執行:

(3)上鎖

23.通訊機制:

訊號量和管程不能傳遞大量資訊,不適合多處理器的情況

引入“訊息傳遞”機制  send recieve

適用於:分散式系統、基於共享記憶體的多處理器機系統……

訊息傳遞;共享記憶體;管道;套接字;遠端呼叫

24.訊息傳遞:

訊息緩衝區結構:訊息頭(訊息型別,接受程序ID,傳送程序ID,訊息長度,控制資訊);訊息體(訊息內容)

25.共享記憶體:

在實體記憶體中建立共享記憶體,對映到兩個程序的地址空間

26.管道 PIPE

利用一個緩衝傳輸介質--記憶體活檔案連線兩個互相通訊的程序

字元流方式寫入讀出

先進先出順序

管道通訊進位制必須提供協調能力:互斥、同步;判斷對方程序是否存在

27。不同OS中程序通訊(尼瑪……終於學到這裡了,去年這會背的是一臉懵逼啊

UNIX:管道、訊號佇列、共享記憶體、訊號量、訊號、套接字

Linux:管道、訊息佇列、共享記憶體、訊號量、訊號、套接字

核心同步機制:原子操作、自旋鎖、讀寫鎖、訊號量(讀取訊號量,互斥體)、遮蔽、BKL

windows:

同步物件:互斥物件、事件物件、訊號量物件、臨界區物件、互鎖變數

套接字、檔案對映、管道、有名管道、郵件槽、剪貼簿、動態資料交換、物件連線與嵌入、動態連結庫(這居然也算)、遠端過程呼叫

28.Linux的屏障:

一種同步機制;用於對一組執行緒進行協調;應用場景:一組執行緒協同完成一項任務,需要所有執行緒都到達一個匯合點後再一起前進推進