信號量PV操作
基本介紹
- 信號量(Semaphore):是表示資源的實體,是一個與隊列有關的整型變量,其值僅能由P、V操作改變。
- 信號量分為:公用信號量和私用信號量。
- 公用信號量:用於實現進程間的互斥,初值通常設為1,它所聯系的一組並發進程均可對它實施P、V操作;
- 私用信號量:用於實現進程間的同步,初始值通常設為0或n,允許擁有它的進程對其實施Р操作。
數據結構
信號量的數據結構:
struct semaphore{
int value; //系統中的資源數
pointer_PCB queue; //阻塞進程隊列
};//PCB表示進程控制塊
//聲明
semaphore s;
PV操作
P(s){//申請資源
if(--s.value<0){
該進程設置為阻塞態
將該進程的PCB插入阻塞隊列s.queue末尾
}
}
V(s){//釋放資源
if(++s.value <= 0){
喚醒相應阻塞隊列s.queue中等待的一個進程
改變其狀態為就緒態
並將其插入就緒隊列
}
}

s. value >= 0時,其值表示還有可用的資源數;
s. value < 0時,其絕對值表示有多少個進程因申請該信號量表示的資源,得不到而進入阻塞態;


解決進程互斥問題

把P1-P3進程的互斥操作都包括在一個PV操作對中
由P2進入

舉例1:


啟發:寫並發進程的時候需要明確互斥區
- 不同進程未進入互斥區時可以並發
- 不同進程進入互斥區時要用PV操作控制
解決進程同步問題
在同步問題中信號量的value值相比於“資源”資源來說,理解為“權限”會更合適,在一個同步問題中,一個進程的執行權限是由它的前驅進程賦予的



代碼實現(以同步問題為例)
為了便於實現,將程序的運行操作也封裝到PV操作中,即
- 如果P操作為信號量申請到權限,那么直接執行信號量所對應的進程
- 如果V操作賦予了信號量權限且信號量的阻塞隊列中有進程,那么直接執行阻塞隊列中的進程

代碼如下:【本人才疏學淺,如有不足懇請斧正】
#include<iostream>
#include<string>
#include<queue>
using namespace std;
/*定義類:process表示一個進程*/
class process{
public :
/*構造函數*/
process() = default;
process(const string &name) : process_name(name){}
process(const process &p) :
process_name(p.process_name){}
/*成員函數*/
//執行進程
void _on(){cout<<process_name+": on"<<endl;}
//關閉進程
void _off() {cout<<process_name+": of"<<endl;}
//進程名
string process_name;
};
/*定義類:semaphore表示信號量*/
/*一個信號量控制一個進程*/
class semaphore{
/*友元聲明:確保PV操作可以訪問semaphore私有成員*/
friend void P(semaphore &s);
friend void V(semaphore &s);
public:
/*構造函數:參數為信號量控制的進程*/
semaphore(const process &p) :
present(p){};
private :
int value = 0; //同步問題value初始化為0
process present; //該信號量控制的進程
queue<process> blocked_processes; //阻塞隊列
};
/*P操作:申請資源(權限)*/
void P(semaphore &s){
--s.value;//申請
if(s.value<0){//無資源(權限):進程進入阻塞隊列
//打印提示信息
cout<<s.present.process_name+" is blocked"<<endl;
//將進程加入阻塞隊列
s.blocked_processes.push(s.present);
}
else{//有資源:直接執行
s.present._on();
}
}
/*V操作:返回資源(給予權限)*/
void V(semaphore &s){
++s.value;//賦予
if(s.value>=0){//如果阻塞隊列有進程:喚醒阻塞進程
if(!s.blocked_processes.empty()){
s.blocked_processes.front()._on();
s.blocked_processes.pop();
}
}
//否則什么也不做
}
//開車進程
process speed_up("speed_up");
//開門進程
process open_door("open_door");
//用兩個信號量分別控制開車進程和開門進程
semaphore OpenDoor(open_door), Speed_Up(speed_up);
int main(){
V(OpenDoor); //賦予開車門的權限
P(OpenDoor); //申請權限:有權限,可以開,打印open_door: on
P(OpenDoor); //申請權限:無權限,開不了門,進入開門阻塞隊列
P(Speed_Up); //申請權限:無權限,開不了車,進入開車阻塞隊列
V(Speed_Up); //賦予權限:執行開車阻塞隊列進程,打印speed_up: on
V(OpenDoor); //賦予權限:執行開門阻塞隊列進程,打印open_door: on
return 0;
}
運行結果:

