1. 程式人生 > 其它 >程序相互作用之訊號量PV操作及其程式碼實現

程序相互作用之訊號量PV操作及其程式碼實現

訊號量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:

啟發:寫併發程序的時候需要明確互斥區

  1. 不同程序未進入互斥區時可以併發
  2. 不同程序進入互斥區時要用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;
}