C++11 Multithreading - The Bounded-Buffer Problem
Condition Variable
The Bounded-Buffer problem, also known as the producer-consumer problem, can be easily solved using the semaphore. In C++, there are no semaphores, but we can use the condition variable instead.
Producer should wait on the full buffer, and Consumer should wait on the empty buffer.
We need a mutex to protect the consistency of the buffer. A condition variable is also needed to notify when the size of buffer changes.
#include <thread> #include <mutex> #include <condition_variable> using namespace std; class BoundedBuffer{ private: deque<int> buffer; int size=10; mutex m; condition_variable cv; public: BoundedBuffer(){}; void produce(int num){ unique_lock<mutex> lock(m); cv.wait(lock,[this](){return buffer.size()<size;}); buffer.push_back(num); cout << "produce " << num << '\n'; cv.notify_all(); } int consume(){ unique_lock<mutex> lock(m); cv.wait(lock,[this](){return buffer.size()>0;}); int res=buffer.front(); buffer.pop_front(); cout << "consume " << res << '\n'; cv.notify_all(); return res; } }; int main(){ BoundedBuffer bf; auto producer=[&](){ for (int i=0;i<5;++i) bf.produce(i); }; auto consumer=[&](){ for (int i=0;i<5;++i) bf.consume(); }; thread producer_thread(producer); thread consumer_thread(consumer); producer_thread.join(); consumer_thread.join(); return 0; }
Semaphore
Using our previously implemented Semaphore and the structure in the OS textbook, we can also solve it.
We assume that the pool consists of n buffers, each capable of holding one item. The mutex semaphore provides mutual exclusion for accesses to the buffer pool and is initialized to the value 1. The empty and full semaphores count the number of empty and full buffers.
The semaphore empty is initialized to the value n; the semaphore full is initialized to the value 0.
#include <thread> #include <mutex> #include <condition_variable> using namespace std; class Semaphore { public: Semaphore(int count_=0):count(count_){} inline void wait(){ std::unique_lock<std::mutex> lock(mtx); cv.wait(lock,[this](){return count > 0;}); count--; } inline void notify(){ std::unique_lock<std::mutex> lock(mtx); count++; cv.notify_one(); } private: std::mutex mtx; std::condition_variable cv; int count; }; class BoundedBuffer { private: deque<int> buffer; Semaphore mutex; Semaphore empty; Semaphore full; public: BoundedBuffer(int size):mutex(1),empty(size),full(0){}; void produce(int num){ empty.wait(); mutex.wait(); buffer.push_back(num); cout << "produce " << num << '\n'; mutex.notify(); full.notify(); } int consume(){ full.wait(); mutex.wait(); int res=buffer.front(); buffer.pop_front(); cout << "consume " << res << '\n'; mutex.notify(); empty.notify(); return res; } }; int main(){ BoundedBuffer bf(10); auto producer=[&](){ for (int i=0;i<5;++i) bf.produce(i); }; auto consumer=[&](){ for (int i=0;i<5;++i) bf.consume(); }; thread producer_thread(producer); thread consumer_thread(consumer); producer_thread.join(); consumer_thread.join(); return 0; }
Reference
https://codereview.stackexchange.com/questions/84109/a-multi-threaded-producer-consumer-with-c11

浙公网安备 33010602011771号