Multithreading: Producer and Consumer Model

Posted by mrherman on Fri, 04 Oct 2019 16:28:20 +0200

Producer and Consumer Model


One place, two roles, three relationships
A place is a buffer
Two roles refer to producers and consumers
Three relationships refer to:
Mutual exclusion between producers and producers
Mutual exclusion between consumers and consumers
Synchronization and Mutual Exclusion between Producers and Consumers

Advantages of the producer-consumer model:
1. Decoupling: that is, no direct data interaction is required
2. Supporting concurrency: that is, multiple threads can operate in the same place at the same time
3. Support uneven busyness and leisure

All three advantages are provided through this site, but because multiple roles may operate the site at the same time, it is necessary to ensure the safe operation of the site.

Using Blocking Queue + Conditional Variables to Simulate the Implementation of Producer-Consumer Model

#include <iostream>
#include <queue>
#include <pthread.h>
#define MAX_QUEUE   10
class BlockQueue
{   
    private:
        std::queue<int> _queue;
        int _capacity;//Queue is growing dynamically and needs to limit the maximum number of nodes in the queue
        pthread_mutex_t _mutex;
        pthread_cond_t _cond_product;
        pthread_cond_t _cond_consumer;
    public:
	    //Initialization
        BlockQueue(int cap = MAX_QUEUE):_capacity(cap) {
            pthread_mutex_init(&_mutex, NULL);
            pthread_cond_init(&_cond_product, NULL);
            pthread_cond_init(&_cond_consumer, NULL);
        }
        ~BlockQueue() {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond_product);
            pthread_cond_destroy(&_cond_consumer);
        }
		//Producers in the queue
        bool QueuePush(int data) {
            pthread_mutex_lock(&_mutex);
            while(_queue.size() == _capacity) 
				//The queue is full, the producer waits
			{
                pthread_cond_wait(&_cond_product, &_mutex);
            }
            _queue.push(data);
            pthread_cond_signal(&_cond_consumer);
            pthread_mutex_unlock(&_mutex);
        }
		//Consumers out of the queue
        bool QueuePop(int &data) {
            pthread_mutex_lock(&_mutex);
            while(_queue.empty()) 
				//Queue empty, consumer waiting
			{
                pthread_cond_wait(&_cond_consumer, &_mutex);
            }
            data = _queue.front();//Get the first node of the team
            _queue.pop();
            pthread_cond_signal(&_cond_product);
            pthread_mutex_unlock(&_mutex);
        }
};
//Producer entry function
void *thr_product (void *arg)
{
    BlockQueue *q = (BlockQueue*)arg;
    int i = 0;
    while(1) {
        q->QueuePush(i++);//Put data in
        std::cout<<"productor:"<<pthread_self()<<"put data:" << i<<"\n";
    }
    return NULL;
}

//Consumer entry function
void *thr_consumer (void *arg)
{
    BlockQueue *q = (BlockQueue*)arg;//Get parameters
    while(1) {
        int data;
        q->QueuePop(data);//Get the data out
        std::cout<<"consumer:"<<pthread_self()<<"get data:"<<data<<"\n";
    }
    return NULL;
}


int main()
{
    pthread_t con_tid[4], pro_tid[4];
    BlockQueue q;
    int ret;
	//Create four producer threads and four consumer threads, respectively
    for (int i = 0; i < 4; i++) {
        ret = pthread_create(&con_tid[i], NULL, thr_consumer,(void*)&q);
        if (ret != 0) {
            std::cout<<"thread create error\n";
            return -1;
        }
    }
    for (int i = 0; i < 4; i++) {
        ret = pthread_create(&pro_tid[i], NULL, thr_product, (void*)&q);
        if (ret != 0) {
            std::cout<<"thread create error\n";
            return -1;
        }
    }
	
	//To prevent threads from exiting directly, wait here
    for (int i = 0; i < 4; i++) {
        pthread_join(con_tid[i], NULL);
    }
    for (int i = 0; i < 4; i++) {
        pthread_join(pro_tid[i], NULL);
    }
    return 0;
}