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