信號量與管程也是進程間通信的方式。信號量是與鎖在同一層級實現的,是操作系統提供的一種協調共享資源訪問的方法。信號量由操作系統管理,操作系統作為管理者地位是高于進程的。
一、信號量
1、信號量(semaphore):是操作系統提供的一種協調共享資源訪問的方法
①信號是一種抽象數據結構
- 一個整型int(sem),可進行兩個原子操作
- P(): sem–,如果sem<0,等待,否則繼續,類似lock_acquire?
- V(): sem++,如果sem<=0,說明當前有等著的,喚醒掛在信號量上的進程,可以是一個,可以是多個
②信號量的特性
- 信號量是被保護的整數變量。初始化完成后,只能通過P()V()操作修改;由操作系統保證,PV操作時原子操作。
- P()可能阻塞,V()不會阻塞
- 通常假定信號量是公平的,線程不會無線阻塞在P操作,可以假定信號量等待時按照先進先出排隊的。而自旋鎖是無法實現先進先出的,因為它需要占用CPU資源不停查詢鎖是否空閑,無法指定進入臨界區的順序。
2、信號量的實現
二、信號量使用
1、信號量分兩種類型:?
- 二進制信號量:約等于鎖,取值0 or 1?
- 資源信號量:資源數目任何非負值?
- 兩者其實是等價的,可以基于一個構造出另一個
信號量的使用有兩種情況:
- 互斥訪問比如臨界區的互斥訪問控制、
- 條件同步比如線程間的條件等待。互斥訪問如下圖
3、生產者—消費者問題
生產者——>緩沖區——>消費者
①問題描述
- 一個或多個生產者在生成數據后放在一個緩沖區里;
- 單個消費者從緩沖區取出數據處理;
- 任何時刻只能有一個生產者或消費者可訪問緩沖區
②問題分析:
- 任何時刻只能有一個線程操作緩沖區(互斥訪問);
- 緩沖區空時,消費者必須等待生產者(條件同步);
- 緩沖區滿時,生產者必須等待消費者(條件同步)
③信號量描述各個約束
- 二進制信號量mutex
- 資源信號量fullBuffers
- 資源信號量emptyBuffers
如下圖是利用信號量實現的生產者消費者模型。生產者消費者模型的要求是同一時刻只能有一個生產者或消費者訪問緩沖區,生產者只能在緩沖區有空間時才能往里塞數據,消費者只有緩沖區有數據時才能從里面消費數據。

三、管程
管程是一種用于多線程互斥訪問共享資源的程序結構,采用面向對象的方法,簡化線程間的同步控制,保證任意時刻最多只有一個線程執行管程代碼,管程與臨界區的區別是在管程中的線程可臨時放棄管程的互斥訪問,等待事件出現時恢復,而臨界區只有線程退出臨界區才能放棄互斥訪問。
管程與臨界區結構上差別在于多了共享數據,共享數據作為條件變量,如果條件變量的數量為0則跟臨界區完全一樣。進入管程的線程因資源被占用而進入等待狀態,每個條件變量表示一種等待原因,對應著一個等待隊列。管程最重要的兩個操作:wait()和Signal(),wait將自身阻塞在等待隊列中,喚醒一個等待者或釋放管程的互斥訪問,Signal操作將等待隊列中的一個線程喚醒,如果等待隊列為空,則等同空操作。
條件變量(condition variab)
- 條件變量是管程內的等待機制:進入管程的線程因資源被占用而進入等待狀態;每個條件變量表示一種等待原因,對應一個等待隊列;
- wait() 操作:將自己阻塞在等待隊列中,喚醒一個等待者或釋放管程的互斥訪問;
- signal()操作:將自己隊列中的一個線程喚醒;如果等待隊列為空,則等同空操作;
調用管程解決消費者生產者問題?
count記錄了當前BUFFER的數據個數?
先在前后加鎖,因為要保證只有一個線程在臨界區 lock在等待/睡眠的時候通過;lock->Acquire()管程進入和lock->Release()管程釋放;notfull.wait(&lock)釋放鎖。喚醒后獲得鎖。
2、管程條件變量的釋放處理方式
管程條件變量釋放處理方式有兩種如下圖。可以看到Hoare的管程方式是更符合實際使用效果的,但是Hansen管程實現方式少了一次進程上下文切換,因此真實OS中一般使用Hansen管程方式。