【操作系統】經典的同步問題(生產者消費者問題, 哲學家進餐問題, 讀寫問題)

来源:http://www.cnblogs.com/libra-yong/archive/2017/06/11/6985526.html
-Advertisement-
Play Games

用專業術語來說, 進程是程式的一次動態執行.說簡單點, 就是進程是系統中的某個任務.操作系統中有多個任務需要執行, 那麼怎樣執行才能使它們同步呢? 即如何讓任務併發執行互不影響呢? 這就引出了進程同步中的經典問題: 生產者消費者問題, 哲學家進餐問題, 讀寫問題 生產者-消費者問題 有一群生產者進程 ...


用專業術語來說, 進程是程式的一次動態執行.說簡單點, 就是進程是系統中的某個任務.操作系統中有多個任務需要執行, 那麼怎樣執行才能使它們同步呢? 即如何讓任務併發執行互不影響呢? 這就引出了進程同步中的經典問題: 生產者消費者問題, 哲學家進餐問題, 讀寫問題

 

生產者-消費者問題

有一群生產者進程在生產產品, 並將這些產品提供給消費者進程取消費. 為使生產者進程與消費者進程能併發進行, 在兩者間設置了一個具有n個緩衝區的緩衝池, 生產者進程將其所生產的產品翻入緩衝區中, 消費者進程可從一個緩衝區中取走產品取消費.生產者消費者進程都以非同步方式進行, 但它們之間必須保持同步, 不允許消費者進程到空緩衝區去取產品, 也不允許生產者進程向已滿的緩衝區投放產品.

一個緩衝池中有n個緩衝區, 只要緩衝池未滿, 生產者便可以投放產品; 緩衝池為空, 消費者便可以消費產品

法一:記錄型信號量

//生產者消費者問題
//記錄型信號量
//緩衝池中有n個緩衝區, 互斥信號量mutex, 
//信號量empty表示空緩衝區數量, full表示滿緩衝區的數量
int in = out = 0;
item buffer[n];
semaphore mutex = 1, empty = n, full = 0;
void producer() {
    do {
        producer an item nextp;
        wait(empty);
        wait(mutex);
        buffer[in] = nextp;
        in = (in + 1) % n;
        signal(mutex);
        signal(full);
    } while(true);
}
void consumer() {
    do {
        wait(full);
        wait(mutex);
        nextc = buffer[out];
        out = (out + 1) % n;
        signal(mutex);
        signal(empty);
        consumer the item in nextc;
    } while(true);
}
void main() {
    cobegin
        producer();
        consumer();
    coend
}

註意: 對信號量的wait()和signal()操作必定是成對出現的.

法二:AND型信號量

//AND型信號量
//Swait(empty, mutex)代替wait(empty)和wait(mutex)
//Ssignal(mutex,full)代替signal(mutext)和signal(full)
//Swait(full, mutex)代替wait(full)和wait(mutex)
//Ssignal(mutex, empty)代替signal(mutex)和signal(empty)
int in = out = 0;
item buffer[n];
semaphore mutex = 1, empty = n, full = 0;
void producer() {
    do {
        producer an item nextp;
        Swait(empty, mutex);
        buffer[in] = nextp;
        in = (in + 1) % n;
        Ssignal(mutex, full);
    } while(true);
}
void consumer() {
    do {
        Swait(full, mutex);
        nextc = buffer[out];
        out = (out + 1) % n;
        Ssignal(mutex, empty);
        consumer the item in nextc;
    } while(true);
}
void main() {
    cobegin
        producer();
        consumer();
    coend
}

 

法三: 管程

//管程
//建立管程producerconsumer,PC
/*
put(x), 生產者利用該過程將自己生產的產品投放到緩衝池中, 並用整型變數count表示緩衝池中已有的產品數目,當
count>=N時, 表示緩衝池已滿,生產者需等待.
get(x), 消費者利用該過程從緩衝池中取出一個產品, 當count<=0時, 表示緩衝池已無可用的產品, 消費者需等待
condition 為notfull和notempty
cwait(condition), 當管程被一個進程占用時, 其他進程調用該進程時阻塞, 並掛在條件condition的隊列上
csignal(condition), 喚醒在cwait執行後阻塞在條件condition隊列上的進程, 如果這樣的進程不止一個, 則選擇其中一個
實施喚醒操作, 如果隊列為空, 則無操作而返回.
*/
Monitor producerconsumer {
    item buffer[N];
    int in, out;
    condition notfull, notempty;
    int count;
    public:
        void put(item x) {
            if (count >= N) cwait(notfull);
            buffer[in] = x;
            in = (in + 1) % N;
            count++;
            ssignal(notempty);
        }
        void get(item x) {
            if (count <= 0) cwait(notempty);
            x = buffer[out];
            out = (out + 1) % N;
            count--;
            csignal(notfull);
        }
        {
            in = 0;
            out = 0;
            count = 0;
        }
}PC;

void producer() {
    item x;
    while (true) {
        producer an item in nextp;
        PC.put(x);
    }
}
void consumer() {
    item x;
    while (true) {
        PC.get(x);
        consumer the item in nextc;
    }
}
void main() {
    cobegin
        producer();
        consumer();
    coend
}

 

哲學家進餐問題

五個哲學家公用一張圓桌, 分別坐在周圍的五張桌子上, 在圓桌上有五個碗和五隻筷子交叉排列, 它們的生活方式是交替的進行思考和進餐. 哲學家進行思考時不用筷子, 饑餓時取一隻他兩邊的任意一隻筷子(預設取左邊的筷子, 沒有時取右邊的, 都沒有時就取不了), 當他有兩隻筷子時就能進餐. 進餐後, 放下筷子繼續思考.若只有一隻筷子, 不放棄該筷子並等待擁有另一隻筷子時再進餐.

用一個信號量表示一隻筷子, 共五個信號量 semaphore chopsitck[5] = {1, 1, 1, 1, 1}; , 為 1 表示筷子未拿起, 為0表示筷子被拿起.那麼第i為科學家的進餐活動就可以描述為

法一:記錄型信號量

do {
    wait(chopstick[i]);
    wait(chopstick[(i + 1) % 5]);
    //eat
    signal(chopstick[i]);
    signal(chopstick[(i + 1) % 5]);
    //think
} while (true);

假設五位哲學家都要拿筷子(都拿左手邊), 那麼將沒有人可以 用餐, 就會陷入死鎖狀態.則哲學家進餐的解決方法:

1.至多允許四位哲學家拿同一邊的筷子, 則可讓至少一位哲學家先用餐, 用餐完後釋放筷子進而讓其他哲學家有機會用餐.

2.五位哲學家先競爭奇數(偶數)好筷子, 在競爭偶數(奇數)號筷子, 總會有一位哲學家能進餐.

 

法二: AND型信號量

//AND型信號量
semaphore chopstick[5] = {1, 1, 1, 1, 1};
do {
    //think
    Swait(chopsitck[(i + 1) % 5], chopsitck[i]);
    //eat
    Ssignal(chopsitck[(i + 1) % 5], chopsitck[i]);
} while (true);

 

 

讀者-寫者問題

一個數據文件或記錄可被多個進程所共用, 則我們稱這個文件或記錄為共用對象.讀文件的進程稱為Reader進程, 寫文件的進程稱為Writer進程.共用對象可以被多個Reader進程, 因為讀進程並不會破壞數據, 但是Writer進程在任何時刻只能有一個, 且須與其他對象互斥的訪問共用對象, 否則多個寫進程會造成衝突. 讀寫者問題即一個Writer進程必須與其他進程互斥的訪問共用對象.

設置寫互斥信號量wmutex

設置讀互斥信號量rmutex

整型變數readcount表示正在讀的進程數目(Reader)

當readcount!=0時, 表示有Reader進程,此時不能進行Writer進程.

法一:

//記錄型信號量
semaphore rmutext = 1, wmutext = 1;
int readcount = 0;
void Reader() {
    do {
        wait(rmutex);
        if (readcount == 0) {
            wait(wmutex);
        }
        readcount++;
        signal(rmutex);
        
        perform read operation;
        
        wait(rmutex);
        readcount--;
        if (readcount == 0) {
            signal(wmutext);
        }
        signal(rmutex);
    } while (true);
}

void Writer() {
    do {
        wait(wmutex);
        perform write operation;
        signal(wmutex);
    } while (true);
}
void main() {
    cobegin
        Reader();
        Writer();
    coend
}

 

 

法二:

引入RN, 表示最多允許RN個Reader進程同時讀

信號量L初始為RN

//信號量集
int RN;
semaphore L = RN, mx = 1;
void Reader() {
    do {
        Swait(L, 1, 1);
        Swait(mx, 1, 0);
        
        perform read operation;
        
        Ssignal(L, 1);
    } while (true);
}
void Writer() {
    do {
        Swait(mx, 1, 1; L, RN, 0);
        perform write operation;
        Ssignal(mx, 1);
    } while (true);
}

void main() {
    cobegin
        Reader();
        Writer();
    coend
}

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 下麵來說說如何用不用消息隊列來進行進程間的通信,消息隊列與命名管道有很多相似之處。有關命名管道的更多內容可以參閱我的另一篇文章:Linux進程間通信——使用命名管道 一、什麼是消息隊列 消息隊列提供了一種從一個進程向另一個進程發送一個數據塊的方法。 每個數據塊都被認為含有一個類型,接收進程可以獨立地 ...
  • 配置vim配置 編輯配置文件 配置如下 主要配置為自動換行,設置行號,設置tab鍵為4個空格,同時將tab鍵自動轉換成空格 ...
  • 參考資料: Nginx中文文檔: http://www.nginx.cn/nginxchscommandline Nginx的啟動、停止、平滑重啟、信號控制和平滑升級:http://zachary-guo.iteye.com/blog/1358312 命令行參數: 常用命令: -c filename ...
  • 官網安裝教程鏈接:https://docs.openstack.org/developer/devstack/ 我在ubuntu14.04 LTS 桌面版/伺服器版都安裝DevStack成功後,在這裡記錄下安裝過程。 介紹下安裝環境: VMware Workstation Pro 12 ubuntu ...
  • 1. 安裝完整的vim# apt-get install vim-gnome 2. 安裝ctags,ctags用於支持taglist,必需!# apt-get install ctags 3. 安裝taglist#apt-get install vim-scripts#apt-get install ...
  • 家裡電腦是Win10的,原來可以在公司通過遠程桌面訪問,最近自動升級了一次補丁後,遠程可以連接,但是輸入正確的用戶密碼後總提示憑據錯誤 (Win10是被訪問的一方,修改的也是被訪問的機器) 修複方式為 命令:gpedit.msc 打開“本地組策略編輯器” Windows設置->安全設置->本地策略- ...
  • Linux系統IO中write原型為 ssize_t write(int filedes, const void * buff, size_t nbytes) ; 當調用write寫數據的時候,調用完成後write直接返回,但是磁碟是個慢速設備,操作系統會將數據保存在內核中的緩衝區中,並負責非同步地將 ...
  • 定義 進程的典型定義:進程是程式的一次動態執行 進程在傳統OS中的定義: 進程是進程實體的運行過程,是系統進行資源分配和調度的獨立單位. 一般情況下,我們所說的進程實體(也叫進程映像)簡稱進程,進程實體包括程式段,數據段和進程式控制制塊(PCB). PCB 創建進程的實質就是創建PCB,撤銷進程實質也是 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...