#include #include #include #include #include #include #include using namespace std; const int MAX_SIZE = 8; const int MAX_COUNT = 30; const int PRODUCE_RATE = 2; const int CONSUME_RATE = 5; mutex queue_mutex; condition_variable condition_not_full; condition_variable condition_done_or_not_empty; queue q; int content = 0; bool producer_done = false; bool queue_done_or_not_empty() { return producer_done || !q.empty(); } bool queue_not_full() { return q.size() < MAX_SIZE; } /** * Produce every few seconds. */ void producer() { while (content < MAX_COUNT) { this_thread::sleep_for(std::chrono::seconds(rand()%PRODUCE_RATE)); // Wait until the queue is not full. unique_lock lock(queue_mutex); condition_not_full.wait(lock, queue_not_full); // Produce. q.push(++content); printf("Producer: %2d (%ld)\n", content, q.size()); // Notify consumers the queue is no longer empty. if (q.size() == 1) condition_done_or_not_empty.notify_all(); lock.unlock(); } producer_done = true; condition_done_or_not_empty.notify_all(); printf("Producer: DONE.\n"); } /** * Consume every few seconds. */ void consumer(int id) { while (true) { this_thread::sleep_for(std::chrono::seconds(rand()%CONSUME_RATE)); // Wait until the queue is not empty. unique_lock lock(queue_mutex); condition_done_or_not_empty.wait(lock, queue_done_or_not_empty); if (!q.empty()) { // Consume. int data = q.front(); q.pop(); for (int i = 1; i <= id; i++) cout << " "; printf("Consumer #%d: %2d (%ld)\n", id, data, q.size()); // Notify the producer the queue is no longer full. if (q.size() == MAX_SIZE-1) condition_not_full.notify_one(); lock.unlock(); } else { lock.unlock(); break; } } for (int i = 1; i <= id; i++) cout << " "; printf("Consumer #%d: DONE.\n", id); } int main() { srand(time(NULL)); thread producer_thread(producer); thread consumer_thread_1(consumer, 1); thread consumer_thread_2(consumer, 2); thread consumer_thread_3(consumer, 3); producer_thread.join(); consumer_thread_1.join(); consumer_thread_2.join(); consumer_thread_3.join(); cout << "Program done." << endl; return 0; }