Уведомление о потоке не работает для моего потребителя

У меня есть попытка на производителя / потребителя

Режиссер

#pragma once
#ifndef PRODUCER_H
#define PRODUCER_H

#include <thread>
#include "Mailbox.h"

class Producer
{
private:
    std::thread producer;
    Mailbox& mailbox;
public:
    Producer(Mailbox& newmailbox);
    ~Producer();
    void start();
    void run();
};

Producer::Producer(Mailbox& newMailbox) : mailbox(newMailbox) {}

Producer::~Producer() {}

void Producer::start()
{
    producer = std::thread(&Producer::run, this);
}

void Producer::run()
{
    mailbox.inc();
}

#endif

потребитель

#pragma once
#ifndef CONSUMER_H
#define CONSUMER_H

#include "Mailbox.h"
#include <thread>
#include <iostream>

class Consumer
{
private:
    Mailbox& mailbox;
    std::thread consumer;
public:
    Consumer(Mailbox& newMailbox);
    ~Consumer();
    void start();
    void run();
};

Consumer::Consumer(Mailbox& newMailbox) : mailbox(newMailbox) {}


Consumer::~Consumer() {}

void Consumer::start()
{
    consumer = std::thread(&Consumer::run, this);
}

void Consumer::run()
{
    mailbox.read();
}

#endif

почтовый ящик

#pragma once
#ifndef MAILBOX_H
#define MAILBOX_H

#include <mutex>
#include <iostream>

class Mailbox
{
private:
    int& mailbox;
    int init_val;
    std::mutex mmutex;
    std::condition_variable condition;
public:
    Mailbox();
    ~Mailbox();
    void inc();
    void read();
};

Mailbox::Mailbox() : mailbox(init_val), init_val(0) {}

Mailbox::~Mailbox()
{

}

void Mailbox::inc()
{   
    int count = 0;
    while (count < 10)
    {

        std::unique_lock<std::mutex> lock(mmutex);
        std::cout << "Producer increment\n";
        mailbox += 1;
        lock.unlock();

        count += 1;
    }

}

void Mailbox::read()
{
    int count = 0;
    while (count < 10)
    {

        std::unique_lock<std::mutex> lock(mmutex);

        condition.wait(lock, [this](){return get_cflag(); });

        condition.notify_one();

        count += 1;

    }

}

#endif

Главный

int main()
{

    Mailbox* mailbox = new Mailbox();
    Consumer* consumer = new Consumer(*mailbox);
    Producer* producer = new Producer(*mailbox);

    consumer->start();
    producer->start();

    return 0;
}

Блокировка мьютекса работает, хотя и асинхронно, потому что я не могу контролировать, когда std::thread начнется, поэтому я решил реализовать полусинхронную методологию, используя std::unique_lock в дополнение к std::mutex,

Проблема в том, что Потребитель ждет, а Производитель улетает вперед без уведомления, по крайней мере, так говорит мне отладчик, а последний результат итерации Производителя грешит на abort(), так что здесь что-то идет не так.

2 ответа

Я не C++ парень, но если эти условные переменные работают так, как я думаю, то вы получите уведомление только в том случае, если во время ожидания поступит сигнал. Если сигнал поступил до того, как вы начали ждать, вы будете блокироваться на неопределенный срок.

После того, как вы получили блокировку в "Mailbox::read", вы должны проверить, доступен ли элемент, и ожидать переменную условия только в том случае, если ее нет. Если есть, продолжайте и возьмите это:

int Mailbox::read()
{
    std::unique_lock<std::mutex> lock(m);
    while (mailbox <= 0)
        condition.wait(lock);
    return mailbox--;
}

Основываясь на комментариях Дэвида Шварца, взгляде Майка Штробеля и дополнительных исследованиях, я изменил функции производителя и потребителя.

Режиссер

void Mailbox::inc()
{   
    int count = 0;
    while (count < 10)
    {

        std::unique_lock<std::mutex> lock(mmutex);
        std::cout << "Producer increment\n";
        mailbox += 1;
        lock.unlock();
        set_cflag(true); // signal to the consumer data is ready
        condition.notify_one();

        {
            std::unique_lock<std::mutex> lock(mmutex);
            condition.wait(lock, [this]() {return get_pflag(); });
        }

        set_pflag(false);

        count += 1;
    }

}

потребитель

 void Mailbox::read()
{
    int count = 0;
    while (count < 10)
    {

        std::unique_lock<std::mutex> lock(mmutex);

        condition.wait(lock, [this](){return get_cflag(); });

        std::cout << "Consumer: " << mailbox << "\n";
        lock.unlock();

        set_pflag(true);
        condition.notify_one();

        count += 1;

        set_cflag(false);

    }

}

почтовый ящик

class Mailbox
{
private:
    int& mailbox;
    int cflag, pflag;
    int init_val;
    std::mutex mmutex;
    std::condition_variable condition;
public:
    Mailbox();
    ~Mailbox();
    int get_cflag() { return cflag; }
    void set_cflag(int newFlag) { cflag = newFlag; }
    int get_pflag() { return pflag; }
    void set_pflag(int newFlag) { pflag = newFlag; }
    void inc();
    void read();
};

Mailbox::Mailbox() : mailbox(init_val), init_val(0), cflag(0), pflag(0) {}

Mailbox::~Mailbox()
{

}

Вывод на исполнение, как я хотел

int main()
{

    Mailbox* mailbox = new Mailbox();
    Consumer* consumer = new Consumer(*mailbox);
    Producer* producer = new Producer(*mailbox);

    consumer->start();
    producer->start();

    fgetc(stdin);

    return 0;
}

Приращение производителя

Потребитель: 1

Приращение производителя

Потребитель: 2

Приращение производителя

Потребитель: 3

Приращение производителя

Потребитель: 4

Приращение производителя

Потребитель: 5

Приращение производителя

Потребитель: 6

Приращение производителя

Потребитель: 7

Приращение производителя

Потребитель: 8

Приращение производителя

Потребитель: 9

Приращение производителя

Потребитель: 10

Другие вопросы по тегам