C++多線程 生產者 消費者示例


之前寫過一篇關於多線程的https://blog.csdn.net/qq_21049875/article/details/79589126。
  為了復習一下C++多線程的使用,以及程序的編寫,於是寫了一個生產者與消費者。
  在編寫的過程中了解了條件變量(std::condition_variable)的使用,可以讓線程掛起和叫醒線程,以及之前編寫一些示例代碼的時候一直用的是std::locak_guard,而不是std::unique_lock,兩者都是RAII(獲取資源立即初始化 ),而后者比較靈活,提供了lock(),unlock(),try_lock(),接口。
  std::unique_lock的源代碼中大概是封裝了mutex的一些接口,下面從其他博客復制了mutex的接口信息。)
  lock(),調用線程將鎖住該互斥量。線程調用該函數會發生下面 3 種情況:
    (1). 如果該互斥量當前沒有被鎖住,則調用線程將該互斥量鎖住,直到調用 unlock之前,該線程一直擁有該鎖。
    (2). 如果當前互斥量被其他線程鎖住,則當前的調用線程被阻塞住。
    (3). 如果當前互斥量被當前調用線程鎖住,則會產生死鎖(deadlock)。
  unlock(), 解鎖,釋放對互斥量的所有權。
  try_lock(),嘗試鎖住互斥量,如果互斥量被其他線程占有,則當前線程也不會被阻塞。線程調用該函數也會出現下面 3 種情況:
    (1). 如果當前互斥量沒有被其他線程占有,則該線程鎖住互斥量,直到該線程調用 unlock 釋放互斥量。
    (2). 如果當前互斥量被其他線程鎖住,則當前調用線程返回 false,而並不會被阻塞掉。
    (3). 如果當前互斥量被當前調用線程鎖住,則會產生死鎖(deadlock)。

  下面代碼編寫中碰到的問題,在productItem與consumeItem的時候,都有對互斥量mtx上鎖的過程,在productItem的代碼里有一個Sleep,是為了讓消費者能夠消費到商品,要不然就由於計算機速度太快,直接生產滿了,就碰到while(item…)直接出發is_full造成后面運行后生產者進入死鎖狀態。
  當然,你可以編寫一個對is_full這個條件變量相應的函數,比如item滿了就扔掉一個,去解鎖is_full然后喚醒product線程,這樣就不需要Sleep函數啦~
  還有,可以用std::this_thread::yield()來實現把執行的線程時間片讓給其他線程使用,就比如item滿了之后讓其他線程運行,或者是std::this_thread::sleep_for() 讓線程睡一下,更或者直接sleep……hah….

代碼:

#include<iostream>
#include<vector>
#include<thread>
#include<queue>
#include<mutex>
#include<Windows.h>

class demo {
private:
condition_variable is_full;
condition_variable is_empty;
mutex mtx;
vector<std::thread> tpool;
private:
queue<int> item_buff;
const int buffsize;
static int item_id;
int c_no, p_no;
private:
void producItem() {
while (true) {
std::unique_lock<mutex> lck(mtx);
while (item_buff.size() == buffsize) {
is_full.wait(lck);
}
item_id = item_id++ %buffsize;
item_buff.push(item_id);
cout << "product item id: " << item_id << endl;
lck.unlock();
is_empty.notify_all();
Sleep(10);
}
}
void consumeItem() {
while (true) {
std::unique_lock<mutex> lck(mtx);
while (item_buff.empty()) {
cout << "wait product" << endl;
is_full.notify_one();
is_empty.wait(lck);
}
cout << "customer id : " << this_thread::get_id() << endl;
cout << "consume Item id: " << item_buff.front() << endl;
item_buff.pop();
lck.unlock();
}
}
public:
demo(int size = 10, int pno = 1, int cno = 5) :buffsize(size), p_no(pno), c_no(cno) {};
void run() {
productTask();
customerTask();
for (auto &i : tpool) {
i.join();
}
}
void productTask() {
for (int i = 0; i < p_no; i++) {
tpool.emplace_back(thread(&demo::producItem, this));
}
}
void customerTask() {
for (int i = 0; i < c_no; i++) {
tpool.emplace_back(thread(&demo::consumeItem, this));
}
}
};

int demo::item_id = 0;

int main()
{
demo t;
t.run();
return 0;
}


免責聲明!

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



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