Home > Enterprise >  C Producer Consumer Problem with condition variable mutex pthreads
C Producer Consumer Problem with condition variable mutex pthreads

Time:11-16

I'm need to do the producer consumer problem in c , solve for 1 consumer and 6 producer, and for 1 producer and 6 consumer, below is the statement of the question.

Question 1: Imagine that you are waiting for some friends in a very busy restaurant and you are watching the staff, who wait on tables, bring food from the kitchen to their tables. This is an example of the classic "Producer-Consumer'' problem. There is a limit on servers and meals are constantly produced by the kitchen. Consider then that there is a limit on servers (consumers) and an "unlimited" supply of meals being produced by chefs (producers).

One approach to facilitate identification and thus reduce to a "producer-consumer" problem is to limit the number of consumers and thus limit the infinite number of meals. produced in the kitchen. Thus, the existence of a traffic light is suggested to control the production order of the meals that will be taken by the attendants.

The procedure would be something like:

  1. Create a semaphore;
  2. Create the server and chef threads;
  3. Produce as many meals as you can and keep a record of how many meals are in the queue;
  4. The server thread will run until it manages to deliver all the meals produced in the tables; and
  5. Threads must be "joined" with the main thread.

Also consider that there are 6 chefs and 1 attendant. If you want, you can consider that a chef takes 50 microseconds to produce a meal and the server takes 10 microseconds to deliver the meal on the table. Set a maximum number of customers to serve. Print on the screen, at the end of the execution, which chef is most and least idle and how many meals each chef has produced.

Question 2: Considering the restaurant described above. Now consider that there are 1 chef and 6 attendants. Assume that a chef takes 50 microseconds to produce a meal and the server takes 15 microseconds to deliver the meal to the table. Set a maximum number of customers to serve. Print which server is the most and least idle and how many meals each server has delivered.

I managed to solve for 6 producers and 1 consumer, but for 6 consumers and 1 producer it's not working, it seems that the program gets stuck in some DeadLock. I'm grateful if anyone knows how to help.

#include <iostream>
#include <random>
#include <chrono>
#include <thread>
#include <mutex>
#include <deque>

//The mutex class is a synchronization primitive that can be used to protect shared data
//from being simultaneously accessed by multiple threads.
std::mutex semaforo;                       //semafoto para fazer o controle de acesso do buffer
std::condition_variable notifica;          //variavel condicional para fazer a notificação de prato consumido/consumido
std::deque<int> buffer;                    //buffer de inteiros
const unsigned int capacidade_buffer = 10; //tamanho do buffer
const unsigned int numero_pratos = 25;     //numeros de pratos a serem produzidos

void produtor()
{
    unsigned static int contador_pratos_produzidos = 0;
    while (contador_pratos_produzidos < numero_pratos)
    {
        std::unique_lock<std::mutex> locker(semaforo);
        notifica.wait(locker, []
                      { return buffer.size() < capacidade_buffer; });
        std::this_thread::sleep_for(std::chrono::microseconds(50));
        buffer.push_back(contador_pratos_produzidos);
        if (contador_pratos_produzidos < numero_pratos)
        {
            contador_pratos_produzidos  ;
        }
        locker.unlock();
        notifica.notify_all();
    }
}

void consumidor(int ID, std::vector<int> &consumido)
{
    unsigned static int contador_pratos_consumidos = 0;
    while (contador_pratos_consumidos < numero_pratos)
    {
        std::unique_lock<std::mutex> locker(semaforo);
        notifica.wait(locker, []
                      { return buffer.size() > 0; });
        std::this_thread::sleep_for(std::chrono::microseconds(15));
        buffer.pop_front();
        if (contador_pratos_consumidos < numero_pratos)
        {
            contador_pratos_consumidos  ;
            consumido[ID]  ;
        }
        locker.unlock();
        notifica.notify_one();
    }
}

int main()
{
    //vetor para contagem do consumo de cada garcon
    std::vector<int> consumido(6, 0);

    //vetor de threads garcon(consumidores)
    std::vector<std::thread> consumidores;
    for (int k = 0; k < 6; k  )
    {
        consumidores.push_back(std::thread(consumidor, k, std::ref(consumido)));
    }

    //produtor/chef
    std::thread p1(produtor);

    for (auto &k : consumidores)
    {
        k.join();
    }
    p1.join();

    int mais_ocioso = 200, menos_ocioso = 0, mais, menos;
    for (int k = 0; k < 6; k  )
    {
        std::cout << "Garcon " << k   1 << " entregou " << consumido[k] << " pratos\n";
        if (consumido[k] > menos_ocioso)
        {
            menos = k   1;
            menos_ocioso = consumido[k];
        }
        if (consumido[k] < mais_ocioso)
        {
            mais = k   1;
            mais_ocioso = consumido[k];
        }
    }
    std::cout << "\nO mais ocioso foi o garcon " << mais << " e o menos ocioso foi o garcon " << menos << "\n";
}

CodePudding user response:

The same exact bug exists in both the consumer and the producer function. I'll explain one of them, and the same bug must also be fixed in the other one.

unsigned static int contador_pratos_consumidos = 0;
while (contador_pratos_consumidos < numero_pratos)
{

This static counter gets accessed and modified by multiple execution threads.

Any non-atomic object that's used by multiple execution threads must be properly sequenced (accessed only when holding an appropriate mutex).

If you focus your attention on the above two lines it should be obvious that this counter is accessed without the protection of any mutex. Once you realize that, the bug is obvious: at some point contador_pratos_consumidos will be exactly one less than numero_pratos. When that happens you can have multiple execution threads evaluating the while condition, at the same time, and all of them will happily conclude that it's true.

Multiple execution threads then enter the while loop. One will succeed in acquiring the mutex and consuming the "product", and finish. The remaining execution threads will wait forever, for another "product" that will never arrive. No more products will ever be produced. No soup for them.

The same bug also exists in the producer, except that the effects of the bug will be rather subtle: more products will end up being produced than there should be.

Of course, pedantically all of this is undefined behavior, so anything can really happen, but these are the typical, usual consequences this kind of undefined behavior. Both bugs must be fixed in order for this algorithm to work correctly.

  • Related