C + + WORKAROUND: Multi-threaded synchronization classic case of producer consumer issues

Source: Internet
Author: User
Tags mutex
Copy from Wikipedia:

Producer Consumer Issues (English: Producer-consumer problem), also known as the limited buffering Problem (English: Bounded-buffer problem), is a classic case of multithreading synchronization problems. This problem describes the two threads that share a fixed size buffer-the so-called "producer" and "consumer"-problems that can occur when they actually run. The primary role of the producer is to generate a certain amount of data into the buffer, and then repeat the process. At the same time, consumers consume the data in buffers. The key to this issue is to ensure that producers do not add data when the buffer is full, and consumers do not consume data when the buffer is empty.

To solve this problem, you must let the producer hibernate when the buffer is full (or simply discard the data), and wait until the next time the consumer consumes the data in the buffer, the producer can wake up and start adding data to the buffer. Similarly, you can let consumers hibernate when the buffer is empty, wait until the producer adds data to the buffer, and then wake the consumer.

This article uses a Itemrepository class to represent the product repository, which contains an array and two coordinate ring queues, a Std::mutex member, to ensure that only one thread reads and writes each time (in order to ensure that the printed message is a row, In its idle time also borrowed this mutex ╮(╯▽╰)╭), two std::condition_variable indicate the queue dissatisfaction and the status of not empty, and thus ensure the production of time dissatisfaction, consumption time is not empty.

#pragma once#include <chrono>//std::chrono#include <mutex>//std::mutex,std::unique_lock,std::lock_ Guard#include <thread>//std::thread#include <condition_variable>//std::condition_variable#include <iostream>//std::cout,std::endl#include <map>//std::mapnamespace MyProducerToConsumer {static const int Grepositorysize = 10;//total size of the repository static const int gitemnum = 97;//number of products to produce s Td::mutex produce_mtx, Consume_mtx;//mutex for all the producer thread or consumer thread Std::map<std::thread::id, int> threadperformance;//records of every thread ' s producing/consuming number struct Itemrepository {//repository cl M_itembuffer[grepositorysize];//repository itself (as a circular queue) int m_producepos;//rear posi tion of circular queue int m_consumepos;//head position of circular queue Std::mutex M_mtx;//mutex for Opera Ting the repository std::condition_variable M_repounfull;//indicating that this repository was unfull (then producers can produce items) std::condition_variable    M_repounempty;//indicating that this repository was unempty (then consumers can produce items)}gitemrepo;        void Produceitem (itemrepository *ir, int item) {Std::unique_lock <std::mutex>ulk (IR-&GT;M_MTX);            while ((Ir->m_producepos + 1)% Grepositorysize = = Ir->m_consumepos) {//full (spare one slot for indicating) Std::cout << "reposity are full.            Waiting for consumers ... "<< Std::endl; Ir->m_repounfull.wait (Ulk);//unlocking Ulk and waiting for unfull condition}//when unfull Ir-&gt ; m_itembuffer[ir->m_producepos++] = Item;//procude and shift std::cout << "item No." << Item &LT;&LT ;        "Produced Successfully by" <<std::this_thread::get_id () << "!" << Std::endl;        THREADPERFORMANCE[STD::THIS_THREAD::GET_ID ()]++; if (ir->m_pRoducepos = = grepositorysize)//loop ir->m_producepos = 0; Ir->m_repounempty.notify_all ();//item produced, so it ' s unempty; Notify all Consumers} int Consumeitem (Itemrepository *ir) {Std::unique_lock<std::mutex>ulk (ir->m_m        TX); while (Ir->m_consumepos = = Ir->m_producepos) {//empty std::cout << "Repository is empty.            Waiting for producing ... "<< Std::endl;        Ir->m_repounempty.wait (Ulk);        } int item = ir->m_itembuffer[ir->m_consumepos++]; Std::cout << "Item No." << Item << "Consumed successfully by" <<std::this_thread::get        _id () << "!" << Std::endl;        THREADPERFORMANCE[STD::THIS_THREAD::GET_ID ()]++;        if (Ir->m_consumepos = = grepositorysize) Ir->m_consumepos = 0; Ir->m_repounfull.notify_all ();//item consumed, so it ' s unempty;    Notify all consumers return item; } void ProducerthrEAD () {static int produced = 0;//static variable to indicate the number of produced items while (1) { Std::this_thread::sleep_for (std::chrono::milliseconds);//sleep long enough in case it runs too fast for other th Reads to Procude std::lock_guard<std::mutex>lck (produce_mtx),//auto unlock when break produced            ++;            if (Produced > Gitemnum) break;            GItemRepo.m_mtx.lock ();            Std::cout << "Producing item No." << produced << "..." << Std::endl;            GItemRepo.m_mtx.unlock ();        Produceitem (&gitemrepo, produced);        } gItemRepo.m_mtx.lock (); Std::cout << "Producer thread" << std::this_thread::get_id () << "exited." << Std::end        L    GItemRepo.m_mtx.unlock ();        } void Consumerthread () {static int consumed = 0; while (1) {std::this_thread::sleep_for (Std::chrono::milliseconds (10));           Std::lock_guard<std::mutex>lck (CONSUME_MTX);            consumed++;            if (Consumed > Gitemnum) break;            GItemRepo.m_mtx.lock ();            Std::cout << "Consuming item available ..." << Std::endl;            GItemRepo.m_mtx.unlock ();        Consumeitem (&gitemrepo);        } gItemRepo.m_mtx.lock (); Std::cout << "Consumer thread" << std::this_thread::get_id () << "exited." << Std::end        L    GItemRepo.m_mtx.unlock ();        } void Inititemrepository (itemrepository* ir) {ir->m_consumepos = 0;    Ir->m_producepos = 0;        } void Run () {inititemrepository (&gitemrepo);        Std::thread thdconsume[11];        Std::thread thdproduce[11];        for (auto& t:thdconsume) t = std::thread (consumerthread);        for (auto& t:thdproduce) t = std::thread (producerthread);        for (auto& T:thdconsume) t.join (); for (auto& T:thdproduCE) t.join ();    for (auto& iter:threadperformance) cout << iter.first << ":" << iter.second << Endl; }}

Related articles:

A detailed example of Java producers and consumers

Java Multi-thread concurrent collaborative producer consumer design pattern

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.