Связь между потоками не работает - C ++ - PullRequest
0 голосов
/ 18 сентября 2018

Я пытаюсь написать простой пример классического общения между двумя потоками, производителем и потребителем.Производитель блокирует мьютекс, генерирует случайные строковые сообщения и помещает их в очередь и снимает блокировку.Затем потребитель блокирует мьютекс и печатает эти данные на экране.Почему-то после запуска кода я получаю пустой терминал несколько раз, а затем программа завершается без каких-либо выходов!Вот мой код:

#include <iostream>
#include <stdlib.h>
#include <thread>
#include <mutex>
#include <queue>
#include <random>
#include <string>
#include <cstdlib>

using namespace std;

static mutex mmutex;
static condition_variable mcond;
static queue <string> mqueue;

void consumer() {
    while (true) {
        unique_lock<mutex> lck{mmutex};
        mcond.wait(lck);
        string new_string = "producer has not produced yet ";
        string m = "";
        if (!mqueue.empty()) {
            m = mqueue.front();
            mqueue.pop();
            string new_string = "producer produced " + m;
        }   
        cout << new_string << endl;
        lck.unlock();
    }
}

void producer() {
    while (true) {
        string new_msg = NULL;
        unique_lock<mutex> lck{mmutex};
        int random = rand() % 40 + 40;
        new_msg = "New Random Char is "+static_cast <char> (random);
        mqueue.push(new_msg);
        mcond.notify_one();
    }
}




int main() {

    thread t1{ producer };
    thread t2{ consumer };


    t1.join();
    t2.join();
    cout << "exiting"<<endl;
    system("PAUSE");
    exit(0);
}

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

В целом вы получаете схему синхронизации просто отлично. Кроме этого, код имеет одну ошибку времени выполнения, несколько непреднамеренных последствий работы с std::string s и ненужный (и потенциально вводящий в заблуждение читатель) вызов: unlock() на std::unique_ptr.

после запуска кода я получаю пустой терминал несколько раз, а затем программа завершается без каких-либо выходов

Зависает и завершается из-за присвоения указателя нулю для std::string:

string new_msg = NULL;

Как вы можете см. Здесь , это приведет к тому, что экземпляр std::string попытается получить доступ к этому адресу с нулем: (*

Во-вторых, вы не можете получить то, что хотели, путем объединения строкового литерала с char, как в следующих строках:

string new_string = "producer produced " + m;

и

new_msg = "New Random Char is "+static_cast <char> (random);

Вот рабочая, немного лучше написанная версия ваших потоковых процедур, в которой вы можете увидеть различные допустимые способы инициализации и присвоения std::string, чтобы получить то, что вы хотели. Еще раз обратите внимание, что удаление lck.unlock();, поскольку std::unique_lock - это RAII объект , который высвобождает mutex при его уничтожении в области видимости while. выход как есть:

void consumer() {
    while (true) {
        unique_lock<mutex> lck{ mmutex };
        mcond.wait(lck);
        string new_string;
        if (!mqueue.empty()) {
            string m = mqueue.front();
            mqueue.pop();
            new_string = string("producer produced ") + m;
        }
        else
        {
            new_string = "producer has not produced yet ";
        }
        cout << new_string << endl;
        //lck.unlock(); // <--- Not the intended usage of `unique_lock`
    }
}

void producer() {
    while (true) {
        string new_msg("New Random Char is ");
        unique_lock<mutex> lck{ mmutex };
        int random = rand() % 40 + 40;
        new_msg += static_cast<char>(random);
        mqueue.push(new_msg);
        mcond.notify_one();
    }
}

Выход:

producer produced New Random Char is F
producer produced New Random Char is =
producer produced New Random Char is K
producer produced New Random Char is N
producer produced New Random Char is *
producer produced New Random Char is :
producer produced New Random Char is 3
producer produced New Random Char is O
producer produced New Random Char is @
producer produced New Random Char is E
producer produced New Random Char is I
...
0 голосов
/ 18 сентября 2018

Этот код не в отличной форме.Если вы запустите его в отладчике, вы быстро поймете, почему он останавливается, а это ....

string new_msg = NULL;

Это нарушение доступа, когда байты в 0 (NULL) читаются, чтобы получитьstring.

Исправлено:

string new_msg;  // default value is empty.

После того, как это удалено, есть пара необходимых изменений, чтобы приблизить код к предполагаемому поведению.

new_msg = "New Random Char is "+static_cast <char> (random);

Этоне работает, так как принимает адрес строки и добавляет к ней от 40 до 80 байт.Который перемещается из строки в какое-то «случайное место».Первоначальная совместимость с C здесь достигается, и правильный способ сделать то, что (я полагаю) предназначен для ...

new_msg = string("New Random Char is ") +static_cast <char> (random);

При преобразовании в std::string, + теперь ведет себя как добавлениеоператор.

Наконец, в потребителе ...

string new_string = "producer produced " + m;

должно быть

new_string = "producer produced " + m;

В противном случае переменная new_string, которая используется для отслеживания результатов, не являетсятак же, как переменная, которая читает очередь.

Наконец, в моем тестировании потребитель не поспевал за производителем, и должна быть некоторая форма регулирования и конечного условия.

...