C++ 模擬生產(chǎn)者與消費者模式等

設計并實現(xiàn)一個進程,該進程擁有一個生產(chǎn)者線程和一個消費者線程,它們使用N個不同的緩沖區(qū)(N為一個確定的數(shù)值,例如N=32)犀勒。需要使用如下信號量:
一個互斥信號量,用以阻止生產(chǎn)者線程和消費者線程同時操作緩沖區(qū)列表妥曲;
一個信號量账蓉,當生產(chǎn)者線程生產(chǎn)出一個物品時可以用它向消費者線程發(fā)出信號;
一個信號量逾一,消費者線程釋放出一個空緩沖區(qū)時可以用它向生產(chǎn)者線程發(fā)出信號铸本。

主要程序結構

#include<iostream>
#include<Windows.h>
#include<process.h>
#include<vector>
using namespace std;

// 等價于WINAPI,約定使用stdcall函數(shù)調用遵堵,既被調用者負責清棧
#define STD __stdcall
// 確定緩沖區(qū)大小箱玷,這里選取5怨规,便于展示和說明結果
#define LENGTH 5
// 隨機時間
#define GETMYRAND() (int)(((double)rand()/(double)RAND_MAX)*300)

// 使用臨界區(qū)來同步線程
CRITICAL_SECTION _cr;
//空信號量
HANDLE emptySemaphore = NULL;
//滿信號量
HANDLE fullSemaphore = NULL;
// 緩沖區(qū)Buffer
vector<int> buffer;

// 消費者線程
DWORD STD Consumer(void* lp) {
while(true) {
    //等待判斷緩沖區(qū)滿的信號量
    WaitForSingleObject(fullSemaphore,0xFFFFFFFF);
    //進入臨界區(qū),線程同步锡足,功能同互斥量 
    EnterCriticalSection(&_cr);
    //消費者線程從緩沖區(qū)中取出消費一個資源
    buffer.pop_back();
    //打印當前緩沖區(qū)可用資源數(shù)
    cout << "消費者消費一個資源波丰,當前可用資源數(shù):" << buffer.size() << endl;
    //離開臨界區(qū)
    LeaveCriticalSection(&_cr);
    //釋放判斷緩沖區(qū)空的信號量
    ReleaseSemaphore(emptySemaphore,1,NULL);
    //線程睡眠隨機時間
    Sleep(GETMYRAND());
}
return 0;
}

// 生產(chǎn)者線程
DWORD STD Producer(void* lp) {
while(true){
    //等待判斷緩沖區(qū)空的信號量
    WaitForSingleObject(emptySemaphore, 0xFFFFFFFF);
    //進入臨界區(qū),線程同步舶得,功能同互斥量 
    EnterCriticalSection(&_cr);
    //生產(chǎn)者線程向緩沖區(qū)中生成一個資源
    buffer.push_back(1);
    //打印當前緩沖區(qū)可用資源數(shù)
    cout << "生產(chǎn)者新生產(chǎn)一個資源掰烟,當前可用資源數(shù):" << buffer.size() << endl;
    //離開臨界區(qū)
    LeaveCriticalSection(&_cr);
    //釋放判斷緩沖區(qū)滿的信號量
    ReleaseSemaphore(fullSemaphore, 1, NULL);
    //線程睡眠隨機時間
    Sleep(GETMYRAND());
}
    return 0;
}

int main() {

//創(chuàng)建信號量
emptySemaphore = CreateSemaphore(NULL, LENGTH, LENGTH, NULL);
fullSemaphore = CreateSemaphore(NULL, 0, LENGTH, NULL);

//初始化臨界區(qū)
InitializeCriticalSection(&_cr);
//開啟多線程
HANDLE handles[2];
handles[1] = CreateThread(0, 0, &Producer, 0, 0, 0);
handles[0] = CreateThread(0, 0, &Consumer,  0, 0, 0);

//等待子線程執(zhí)行完畢
WaitForMultipleObjects(2, handles, true, INFINITE); //"Join" trreads
//釋放子線程
CloseHandle(handles[0]);
CloseHandle(handles[1]);
//釋放臨界區(qū)
DeleteCriticalSection(&_cr);
return 0;
}
一、生產(chǎn)者消費者線程互斥

使用critical area(臨界區(qū))來保證生產(chǎn)者和消費者的線程彼此互斥:


圖片.png

在多線程開啟前后分別初始化臨界區(qū)和銷毀臨界區(qū)沐批。
接下來纫骑,在生產(chǎn)者線程函數(shù)和消費者線程函數(shù)對緩沖區(qū)進行操作的代碼前后啟用臨界區(qū)和離開臨界區(qū),來做到兩個線程間互斥同步九孩。

圖片.png

圖片.png

最終效果是先馆,雖然兩個線程都通過死循環(huán)不斷執(zhí)行循環(huán)體中代碼,但是在其中一個線程執(zhí)行臨界區(qū)代碼時躺彬,另一個線程被互斥阻塞煤墙。


圖片.png
二、生產(chǎn)者宪拥、消費者分別在“滿”和“空”時阻塞

生產(chǎn)者線程得到emptySemaphore信號量時,其計數(shù)器-1仿野,開始生產(chǎn)資源。在生產(chǎn)結束后她君,使fullSemaphore的計數(shù)器+1设预。
消費者線程得到fullSemaphore信號量時,其計數(shù)器-1,開始生產(chǎn)資源犁河。在生產(chǎn)結束后,使emptySemaphore的計數(shù)器+1魄梯。
通過上面所述過程桨螺,使用emptySemaphore和fullSemaphore兩個信號量可以做到資源生產(chǎn)滿時生產(chǎn)者阻塞,資源消費完時消費者阻塞的功能酿秸。


圖片.png

圖片.png

為了演示消費者阻塞效果灭翔,我們把生產(chǎn)者的生產(chǎn)效率降低,既在生產(chǎn)者線程結束后辣苏,Sleep睡眠的時間延長肝箱。


圖片.png
查看效果:
圖片.png

每隔大半秒出現(xiàn)一對生產(chǎn)者和消費者記錄回怜,說明資源不足時矢腻,已經(jīng)阻塞消費者繼續(xù)消費資源,而等待生產(chǎn)者Sleep休眠時間之后娃豹,生產(chǎn)出新的資源退客,消費者才繼續(xù)消費骏融。
為了演示生產(chǎn)者阻塞效果链嘀,我們把消費者的消費效率降低,既在消費者線程結束后档玻,Sleep睡眠的時間延長怀泊。


圖片.png
查看效果:
圖片.png

當資源數(shù)到達5時,資源已滿時误趴,既阻塞生產(chǎn)者繼續(xù)生產(chǎn)資源霹琼,而等待消費者Sleep休眠時間之后,消費掉資源凉当,生產(chǎn)者才繼續(xù)生產(chǎn)枣申。

查閱資料及筆記:

在生產(chǎn)者和消費者的代碼中經(jīng)常出現(xiàn)DWORD WINAPI
其中,WINAPI是宏定義 #define WINAPI __stdcall
stdcall是一種函數(shù)調用約定纤怒,其清棧工作由被調用者執(zhí)行糯而,對于節(jié)省內存效果很好,但缺點是參數(shù)不是可變長類型泊窘。
另外還有__cdcel熄驼、__fastcall等。
臨界區(qū)烘豹、互斥量瓜贾、信號量、事件總結:
1. 互斥量與臨界區(qū)的作用非常相似携悯,但互斥量是可以命名的祭芦,也就是說它可以跨越進程使用。所以創(chuàng)建互斥量需要的資源更多憔鬼,所以如果只為了在進程內部是用的話使用臨界區(qū)會帶來速度上的優(yōu)勢并能夠減少資源占用量 龟劲。因為互斥量是跨進程的互斥量一旦被創(chuàng)建,就可以通過名字打開它轴或。
臨界區(qū)的缺點是:沒有辦法知道進入臨界區(qū)中的那個線程是生是死昌跌。如果那個線程在進入臨界區(qū)后當?shù)袅耍覜]有退出來照雁,那么系統(tǒng)就沒有辦法消除掉此臨界區(qū)蚕愤。
2. 互斥量(Mutex),信號量(Semaphore)饺蚊,事件(Event)都可以被跨越進程使用來進行同步數(shù)據(jù)操作萍诱,而其他的對象與數(shù)據(jù)同步操作無關,但對于進程和線程來講污呼,如果進程和線程在運行狀態(tài)則為無信號狀態(tài)裕坊,在退出后為有信號狀態(tài)。所以可以使用WaitForSingleObject來等待進程和 線程退出燕酷。
3. 通過互斥量可以指定資源被獨占的方式使用碍庵,但如果有下面一種情況通過互斥量就無法處理映企,比如現(xiàn)在一位用戶購買了一份三個并發(fā)訪問許可的數(shù)據(jù)庫系統(tǒng),可以根據(jù)用戶購買的訪問許可數(shù)量來決定有多少個線程/進程能同時進行數(shù)據(jù)庫操作静浴,這時候如果利用互斥量就沒有辦法完成這個要求堰氓,信號燈對象可以說是一種資源計數(shù)器。
mutex和samephore都是信號量苹享,但前者實現(xiàn)critical area的功能双絮,后者帶計數(shù)器。mutex可以說是計數(shù)為1的samephore得问。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末囤攀,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宫纬,更是在濱河造成了極大的恐慌焚挠,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漓骚,死亡現(xiàn)場離奇詭異蝌衔,居然都是意外死亡,警方通過查閱死者的電腦和手機蝌蹂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門噩斟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人孤个,你說我怎么就攤上這事剃允。” “怎么了齐鲤?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵斥废,是天一觀的道長给郊。 經(jīng)常有香客問我牡肉,道長,這世上最難降的妖魔是什么丑罪? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮凤壁,結果婚禮上吩屹,老公的妹妹穿的比我還像新娘。我一直安慰自己拧抖,他們只是感情好煤搜,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著唧席,像睡著了一般擦盾。 火紅的嫁衣襯著肌膚如雪嘲驾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天迹卢,我揣著相機與錄音辽故,去河邊找鬼。 笑死腐碱,一個胖子當著我的面吹牛誊垢,可吹牛的內容都是我干的。 我是一名探鬼主播症见,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼喂走,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谋作?” 一聲冷哼從身側響起芋肠,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎遵蚜,沒想到半個月后帖池,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡谬晕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年碘裕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片攒钳。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡帮孔,死狀恐怖,靈堂內的尸體忽然破棺而出不撑,到底是詐尸還是另有隱情文兢,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布焕檬,位于F島的核電站姆坚,受9級特大地震影響,放射性物質發(fā)生泄漏实愚。R本人自食惡果不足惜兼呵,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望腊敲。 院中可真熱鬧击喂,春花似錦、人聲如沸碰辅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽没宾。三九已至凌彬,卻和暖如春沸柔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背铲敛。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工褐澎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人原探。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓乱凿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親咽弦。 傳聞我的和親對象是個殘疾皇子徒蟆,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內容