進程同步---生產者與消費者問題以及進程同步機制--信號量及P、V操作

進程同步 synchronization

描述

指系統中多個進程中發生的時間存在某種時序關關係,需要相互合作,共同完成一項任務。


場景

一個進程運行到某一點時,要求另一個夥伴進程爲它提供消息,在未獲得消息之前,該進程進入阻塞態,獲得消息後被喚醒進入就緒態。*

生產者與消費者問題又稱爲有界緩衝區問題

場景:

  • 一個或者多個生產者生產某種類型的數據放置在緩衝區中
  • 有消費者從緩衝區中取數據,每次取一項
  • 只能有一個生產者貨消費者對緩衝區進行操作

要解決的問題:

  • 當緩衝區已滿時,生產者不會繼續向其中添加數據
  • 當緩衝區爲空時,消費者不會從中移走數據
  • 要避免忙等待,睡眠和喚醒操作(原語)
#define N 100
int count = 0;
void producer(void)
{
    int item;
    while(TRUE)
    {
        item = produce_item();
        if(count == N)         /*判斷緩衝區是否滿了*/
            sleep();
        insert_item(item);
        count = count + 1;
        if(count == 1) /*判斷是否有消費者睡眠*/
            wakeup(consumer);
    }
}

void consumer(void)
{
    int item;
    while(TRUE)
    {
        if(count == 0) /*判斷是否有數據*/
            sleep();
        item = remove_item();
        count = count - 1;
        if(count == N-1) /*判斷是否有生產者睡眠*/
            wakeup(producer);
        consume_item(item);
    }
}

一種經典的進程同步機制–信號量及P、V操作

信號量及P、V操作

  • 一個特殊變量
  • 用於進程間傳遞信息的一個整數值
  • 定義
struct semaphore
{
    int count;
    queueType queue;
}
  • 信號量說明: semaphore s;
  • 對信號量可以實施的操作:初始化、P和V(P、V是指荷蘭語中的test(porberen)和increment(verhogen))
    • P、V操作爲原語操作(Primitive or atomic action)
    • 在信號量上定義了三個操作初始化(非負數)、P操作、V操作
    • 最初提出的是二元信號量(解決互斥)之後推廣到一般信號量(多值)或計數信號量(解決同步)
P(s)
{
    s.count--;
    if(s.count < 0)
    {
        該進程狀態置爲阻塞狀態;
        該進程插入相應的等待隊列s.queue末尾;
        重新調度;
    }
}

V(s)
{
    s.count++;
    if(s.count <= 0)
    {
        喚醒相應的等待隊列s.queue中等待的一個進程;
        改變其狀態爲就緒態,並將其插入就緒隊列;
    }
}

用PV操作解決進程間的互斥問題

  • 分析併發進程的關鍵活動,或定臨界區
  • 設置信號量 mutex,初值爲1
  • 在臨界區前實施P(mutex)
  • 在臨界區之後實施V(mutex)

用信號量解決生產者、消費者問題

#define N 100                   /*緩衝區個數*/
typedef int semaphore;          /*信號量是一種特殊的整數類型*/
semaphore mutex = 1;            /*互斥信號量:控制對臨界區的訪問*/
semaphore empty= N;             /*空緩衝區的個數*/
semaphore full = 0;             /*滿緩衝區個數*/
void producer(void)
{
    int item;
    while(TRUE)
    {
        item = produce_item()
        P(&empty);
        P(&mutex);
        insert_item(item);
        V(&mutex);
        V(&full);

    }

}

void consumer(void)
{
    int item;
    while(TRUE)
    {
        P(&full);
        P(&mutex);
        item = remove_item()
        P(&mutex);
        V(&empty);
        consume_item(item);
    }

}

producer中P(&empty);P(&mutex);中不能顛倒位置會造成死鎖問題。consumer中的V(&mutex);V(&full);V操作位置可以顛倒,不會出錯,但是現在最好,還有consume_item(item);放在臨界區內也行,不會出錯,但是會增加臨界區的發威,現在這種排序的臨界區範圍最小。

發佈了29 篇原創文章 · 獲贊 12 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章