【C++】多线程(链式、循环队列)实现生产者消费者模式
生產(chǎn)者消費(fèi)者模式:
????????生產(chǎn)者消費(fèi)者問題(英語:Producer-consumer problem),也稱有限緩沖問題(英語:Bounded-buffer problem),是一個(gè)多線程同步問題的經(jīng)典案例。該問題描述了兩個(gè)共享固定大小緩沖區(qū)的線程——即所謂的“生產(chǎn)者”和“消費(fèi)者”——在實(shí)際運(yùn)行時(shí)會(huì)發(fā)生的問題。生產(chǎn)者的主要作用是生成一定量的數(shù)據(jù)放到緩沖區(qū)中,然后重復(fù)此過程。與此同時(shí),消費(fèi)者也在緩沖區(qū)消耗這些數(shù)據(jù)。該問題的關(guān)鍵就是要保證生產(chǎn)者不會(huì)在緩沖區(qū)滿時(shí)加入數(shù)據(jù),消費(fèi)者也不會(huì)在緩沖區(qū)中空時(shí)消耗數(shù)據(jù)。
?
這是我在Linux多線程中寫過的一篇文章,里面詳細(xì)講解了信號(hào)量和互斥鎖解決多線程的生產(chǎn)者與消費(fèi)者模式:
Linux信號(hào)量與互斥鎖解決生產(chǎn)者與消費(fèi)者問題_神廚小福貴!的博客-CSDN博客先來看什么是生產(chǎn)者消費(fèi)者問題:生產(chǎn)者消費(fèi)者問題(英語:Producer-consumer problem),也稱有限緩沖問題(英語:Bounded-buffer problem),是一個(gè)多線程同步問題的經(jīng)典案例。該問題描述了兩個(gè)共享固定大小緩沖區(qū)的線程——即所謂的“生產(chǎn)者”和“消費(fèi)者”——在實(shí)際運(yùn)行時(shí)會(huì)發(fā)生的問題。生產(chǎn)者的主要作用是生成一定量的數(shù)據(jù)放到緩沖區(qū)中,然后重復(fù)此過程。與此同時(shí),消費(fèi)者也在緩沖區(qū)消耗這些數(shù)據(jù)。該問題的關(guān)鍵就是要保證生產(chǎn)者不會(huì)在緩沖區(qū)滿時(shí)加入數(shù)據(jù),消費(fèi)者也不會(huì)在緩沖區(qū)中空時(shí)消耗數(shù)據(jù)https://blog.csdn.net/qq_45829112/article/details/121580819下圖就是生產(chǎn)者消費(fèi)者的大致模型:
上圖所示,我們能不能在【C++】中使用多線程使得,一邊生產(chǎn),一邊消費(fèi)呢???
關(guān)于【C++】多線程,我在之前一篇中說過:
【C++】多線程thread_神廚小福貴!的博客-CSDN博客進(jìn)程和線程的區(qū)別:進(jìn)程是資源分配的最小單位,線程是CPU調(diào)度的最小單位 進(jìn)程有自己的獨(dú)立地址空間,線程共享進(jìn)程中的地址空間 進(jìn)程的創(chuàng)建消耗資源大,線程的創(chuàng)建相對(duì)較小進(jìn)程的切換開銷大,線程的切換開銷相對(duì)較小 進(jìn)程:程序執(zhí)行的過程叫進(jìn)程。線程:進(jìn)程內(nèi)部的一條執(zhí)行序列或執(zhí)行路徑,一個(gè)進(jìn)程可以包含多條線程(多線程)!每個(gè)進(jìn)程最少有一個(gè)線程,例如下面代碼:#include <iostream>using namespace std; int main(){ https://blog.csdn.net/qq_45829112/article/details/123521502?spm=1001.2014.3001.5502
下面我們拿鏈隊(duì)列和循環(huán)隊(duì)列分別實(shí)現(xiàn)我們的生產(chǎn)者消費(fèi)者模式
鏈隊(duì)列實(shí)現(xiàn)生產(chǎn)者消費(fèi)者:queue來實(shí)現(xiàn):
const int MAX_ITEM = 20; //雙端隊(duì)列最大長(zhǎng)度
std::mutex mx; //全局鎖
std::condition_variable cv; //條件變量cv
class Queue
{
public:void put(int val, int index) //入隊(duì)函數(shù){std::unique_lock<std::mutex> lock(mx); //類似于智能指針的智能鎖,不需要手動(dòng)解鎖while (q.size() == MAX_ITEM) //隊(duì)列滿了之后,等待{cv.wait(lock);}q.push_back(val); //入隊(duì)cv.notify_all(); //喚醒cout << "producer: " << index << "val : " << "生產(chǎn)者" << val << endl;} int get(int index) //出隊(duì)函數(shù){unique_lock<std::mutex> lock(mx); //類似于智能指針的智能鎖,不需要手動(dòng)解鎖while (q.empty()) //隊(duì)列空了等待{cv.wait(lock);}int val = q.front(); //出隊(duì)函數(shù)q.pop_front(); //隊(duì)頭出,隊(duì)尾加cv.notify_all();cout << "Consumer : " << index << " val : " << val << endl;return val;}
private:deque<int> q;
};
void producer(Queue* q, int index)
{for (int i = 0; i < 100; ++i){q->put(i, index); //調(diào)用class queue中的put函數(shù)std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}
void consumer(Queue* q, int index)
{for (int i = 0; i < 100; ++i){q->get(index); //調(diào)用class queue中的get函數(shù)std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}
int main()
{Queue* q = new Queue();thread p1(producer, q, 1);thread s1(consumer, q, 1);p1.join();s1.join();return 0;
}
這個(gè)代碼也比較簡(jiǎn)單,就不多說了,上面注釋也很詳細(xì)!!!
看一下運(yùn)行結(jié)果:因?yàn)槲以谙M(fèi)者函數(shù)和生產(chǎn)者函數(shù)中的睡眠時(shí)間都是100,所以我們的生產(chǎn)者和消費(fèi)者就是生產(chǎn)一個(gè),消費(fèi)一個(gè)這個(gè)情況
?循環(huán)隊(duì)列實(shí)現(xiàn)生產(chǎn)者消費(fèi)者:
下圖是循環(huán)隊(duì)列的大致示意圖:
?下面來代碼:
template<class T> //模板類
class Queue
{enum { QUSIZE = 8 }; //循環(huán)隊(duì)列大小為8T* data; //指針指向循環(huán)隊(duì)列連續(xù)空間int front; //隊(duì)頭int rear; //隊(duì)尾int size; //當(dāng)前隊(duì)列的元素個(gè)數(shù)int maxsize; //隊(duì)列最大大小
public:Queue() :data(nullptr), front(0), rear(0), size(0), maxsize(QUSIZE){data = new T[maxsize];}~Queue(){free(data);data = nullptr;front = rear = -1;size = 0;maxsize = 0;}int Capt() const { return maxsize; } //求隊(duì)列最大元素個(gè)數(shù)的函數(shù)int Size() const { return size; } //求現(xiàn)有元素個(gè)數(shù)的函數(shù)bool Empty() const { return Size() == 0; } //判空函數(shù)bool Full() const { //判滿函數(shù)return Size() == maxsize;}bool Push(const T& val) //入隊(duì)函數(shù){if (Full()) return false;data[rear] = val;rear = (rear + 1) % maxsize; //上面說到最大值為8,也就是說存儲(chǔ)下標(biāo)為0到7size += 1;return true;}bool Front(T& val) //出隊(duì)函數(shù){if (Empty()) return false;val = data[front];front = (front + 1) % maxsize;//上面說到最大值為8,也就是說存儲(chǔ)下標(biāo)為0到7size -= 1;return true;}
};Queue<int> iq; //實(shí)例化iq
std::mutex mx; //全局鎖mx
std::condition_variable cv; //條件變量cv
const int maxsize = iq.Capt(); //最大元素個(gè)數(shù)int number = 0; // 100;
void producer(int index)
{std::unique_lock<std::mutex> lock(mx); //類似于智能指針的智能鎖for (int i = 0; i < 100; i++){cv.wait(lock, []()->bool {return !iq.Full(); }); //lambda表達(dá)式iq.Push(number); //上述lambda表達(dá)式為真退出,所以就不為full時(shí)為退出cout << "product " << number << endl;number++;cv.notify_all();}
}void consumer(int index)
{std::unique_lock<std::mutex> lock(mx);for (int i = 0; i < 100; i++){cv.wait(lock, []()->bool {return !iq.Empty(); });//lambda表達(dá)式中為真退出等待不為NULL時(shí),退出waitint val = 0;iq.Front(val);cout << "consumer " << val << endl;cv.notify_all();}
}int main(){std::thread pth1(producer, 1); //生產(chǎn)者std::thread pth2(consumer, 2); //消費(fèi)者pth1.join();pth2.join();return 0;
}
運(yùn)行結(jié)果:?
?
總結(jié)
以上是生活随笔為你收集整理的【C++】多线程(链式、循环队列)实现生产者消费者模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 以笑开头的成语有哪些啊?
- 下一篇: 基数排序(桶排序)