I am trying to learn concurrent programming in C++11. I tried to write code for a classic producer consumer concurrency problem. Would you please review and make any comments about it?
#include <iostream>
#include <thread>
#include <deque>
#include <mutex>
#include <chrono>
#include <condition_variable>
using std::deque;
std::mutex mu,cout_mu;
std::condition_variable cond;
class Buffer
{
public:
void add(int num) {
while (true) {
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker, [this](){return buffer_.size() < size_;});
buffer_.push_back(num);
locker.unlock();
cond.notify_all();
return;
}
}
int remove() {
while (true)
{
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker, [this](){return buffer_.size() > 0;});
int back = buffer_.back();
buffer_.pop_back();
locker.unlock();
cond.notify_all();
return back;
}
}
Buffer() {}
private:
deque<int> buffer_;
const unsigned int size_ = 10;
};
class Producer
{
public:
Producer(Buffer* buffer)
{
this->buffer_ = buffer;
}
void run() {
while (true) {
int num = std::rand() % 100;
buffer_->add(num);
cout_mu.lock();
std::cout << "Produced: " << num << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(50));
cout_mu.unlock();
}
}
private:
Buffer *buffer_;
};
class Consumer
{
public:
Consumer(Buffer* buffer)
{
this->buffer_ = buffer;
}
void run() {
while (true) {
int num = buffer_->remove();
cout_mu.lock();
std::cout << "Consumed: " << num << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(50));
cout_mu.unlock();
}
}
private:
Buffer *buffer_;
};
int main() {
Buffer b;
Producer p(&b);
Consumer c(&b);
std::thread producer_thread(&Producer::run, &p);
std::thread consumer_thread(&Consumer::run, &c);
producer_thread.join();
consumer_thread.join();
getchar();
return 0;
}
Buffer::add
's body wrapped in thewhile
for the sake of consistency with the other methods, or is there some reason behind it? It doesn't seem like it's being used for control flow, and it's not introducing a meaningful scope. I'm just wondering if I'm missing some trick or something. \$\endgroup\$buffer_
is full, that thread will put itself into wait or suspended condition (production stops until something is consumed) without wasting the CPU cycles. \$\endgroup\$while
in theBuffer::remove
necessary? Also, if there were nostd::cout
in the Producer and Consumerrun
methods, the cout_mu lock would not be necessary, right? \$\endgroup\$