進程相互作用之信號量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中等待的一個進程
        改變其狀態為就緒態
        並將其插入就緒隊列
    }
}

image-20220301161444189

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

image-20220301161736995image-20220301161859521

解決進程互斥問題

image-20220301162538320

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

由P2進入

image-20220301163902242

舉例1:

image-20220301165711232

image-20220301170125873

啟發:寫並發進程的時候需要明確互斥區

  1. 不同進程未進入互斥區時可以並發
  2. 不同進程進入互斥區時要用PV操作控制

解決進程同步問題

在同步問題中信號量的value值相比於“資源”資源來說,理解為“權限”會更合適,在一個同步問題中,一個進程的執行權限是由它的前驅進程賦予的

image-20220301171408522

image-20220301171611088

image-20220301172201100

代碼實現(以同步問題為例)

為了便於實現,將程序的運行操作也封裝到PV操作中,即

  • 如果P操作為信號量申請到權限,那么直接執行信號量所對應的進程
  • 如果V操作賦予了信號量權限且信號量的阻塞隊列中有進程,那么直接執行阻塞隊列中的進程
    image-20220301184539492

代碼如下:【本人才疏學淺,如有不足懇請斧正】

#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;
}

運行結果:
image-20220301202900044


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM