一、背景
利用信號量和管程解決同步互斥的問題
1.併發問題:競爭條件(競態條件)
- 多程序併發存在大的問題
2.同步
- 線程共享公共數據的協調條件
- 包括互斥與條件同步
- 互斥:在同一時間只有一個線程可以執行臨界區
3.解決同步問題正確比較難
- 需要高層次的編程抽象(如:鎖)
- 從底層硬件支持編譯
二、信號量
1. 抽象數據類型
1)一個整形(sem),兩個原子操作
2)p() 操作:sem減一
- 如果信號量sem<0,認爲執行p操作的進程需要睡眠,等待
- 如果信號量sem>0,認爲執行p操作的進程可以繼續執行,可以進入臨界區
- 如果擋住了,就不能執行後續的程序,起到了一個阻擋的作用。
3)v() 操作:sem加一
- 如果信號量sem<=0,認爲當前的進程等待在這一個信號量上面,然後會喚醒這個進程(一個或多個)
2. 屬性
-
信號量是整數(有符號數)
一開始通常會設定爲一個大於0的數,所以一開始執行p操作不會被阻塞。但是多次執行p操作之後,執行p操
作的進程就會等待在上面。這時需要進程執行v操作,然後喚醒等在這個上面的進程。(如果只能喚醒一個進
程,一般是喚醒第一個等待的進程,FIFO隊列)
-
信號量是被保護的變量
-
初始化完成後,唯一改變一個信號量的值的辦法是通過p操作或者是v操作
-
操作必須是原子
-
-
p操作(信號量減一操作)能夠阻塞,v操作(信號量加一操作)不會阻塞
-
假定信號量是公平的
- 沒有線程被阻塞在p操作仍然阻塞如果v操作被無限頻繁地調用(在同一個信號量)
- 在實踐中,FIFO經常被使用
3. 兩種類型信號量
- 二進制信號量:可以是0或1(與前面的lock達到同樣的效果)
- 一般/計數信號量:可取任何非負值
- 兩者互相表現(給定一個可以實現另一個)
4. 注意
- 信號量可以用在兩個方面
- 互斥
- 條件同步(調度約束–一個線程等待另一個線程的事件發生)
- 讀/開發代碼比較困難
- 容易出錯
- 使用的信號量已經被另一個線程佔用
- 忘記釋放信號量
- 不能處理死鎖問題
三、管程(moniter)
管程的抽象程度更高,更加容易的來完成相應的同步互斥的問題。
1.定義
管程是包含了一系列的共享變量以及針對這些這些變量函數的一個組合或模塊。 其包括:
- 一個鎖:指定臨界區(確保互斥性,只能有一個線程)
- 0或者多個條件變量:等待/通知信號量用於管理併發訪問共享數據
2. 目的:分離互斥和條件同步的關注
- (一開始是完成編程語言的設計,而不是操作系統的設計的,所以其整體上是針對語言的併發機制來完成的)
3. 一般方法
- 收集在對象/模塊中的相關共享數據
- 定義方法來訪問共享數據