程序相互作用之訊號量PV操作及其程式碼實現
阿新 • • 發佈:2022-03-01
訊號量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 >=O時,其值表示還有可用的資源數;
s. value < O時,其絕對值表示有多少個程序因申請該訊號量表示的資源,得不到而進入阻塞態;
解決程序互斥問題
把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;
}