Проблема с блокировкой и условной переменной в многопоточности c ++ - PullRequest
0 голосов
/ 30 мая 2018

Я пытаюсь реализовать простой пример многопоточности в C ++ (Windows 10, Visual Studio Express).

У меня есть поток T1, который вычисляет z = x * x , гдеx и z - глобальные переменные.Поток T2 отображает z .

Я хотел использовать блокировки и переменную условия.

По какой-то причине выполнение застревает, а T1 не разблокируется (после cv.wait, вероятно, в цикле while - высокая загрузка ЦП).Но это не происходит, когда я добавляю некоторый код (я пробовал с cout << "x" << endl;) перед cv.notify_one(); в main () .Это очень странно.

Заранее спасибо за помощь!

Вот код.Я удалил части, которые я положил, чтобы уничтожить потоки, потому что я не дохожу до этой части алгоритма - проблема раньше.

#include "stdafx.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std;

mutex m;
condition_variable cv;
bool datax = 0, dataz = 0, zPrinted = 0;

void T1(const int& x, int& z)
{
    do {
        unique_lock<mutex> lk(m);
        cv.wait(lk, [] {return (datax); });
        if (datax) {
            z = x * x;
            datax = 0;
            dataz = 1;
            lk.unlock();
            while (dataz)
                cv.notify_one();
        }
    } while (1);
}

void T2(const int& z)
{
    do {
        unique_lock<mutex> lk(m);
        cv.wait(lk, [] {return (dataz); });
        if (dataz) {
            cout << "z = " << z << endl;
            dataz = 0;
            zPrinted = 1;
            lk.unlock();
            while (zPrinted)
                cv.notify_one();
        }
    } while (1);
}

int main()
{
    int x, z;
    char c;
    thread threadT1(T1, cref(x), ref(z));
    thread threadT2(T2, cref(z));
    do {
        unique_lock<mutex> lk(m);
        cout << "Enter x: ";
        cin >> x;
        datax = 1;
        lk.unlock();
        while (datax) {
            cv.notify_one();
        }
        cv.wait(lk, [] {return zPrinted; });
        zPrinted = 0;
        cout << "Continue? (y/n): ";
        cin >> c;
    } while (c == 'y');
    return 0;
}

Ответы [ 2 ]

0 голосов
/ 01 июня 2018

Помимо указанной выше проблемы с ожиданием на разблокированном мьютексе:

cv.wait(lk, [] {return zPrinted; });

у вас есть потоки, которые не воссоединены и работают с бесконечными циклами.Вот рабочая версия с модами для исправления этих проблем:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std;

mutex m;
condition_variable cv;
bool datax = 0, dataz = 0, zPrinted = 0;
bool kill = 0;

void T1(const int& x, int& z)
{
    do {
        unique_lock<mutex> lk(m);
        cv.wait(lk, [] {return (datax+kill); });
        if (kill) return;
        if (datax) {
            z = x * x;
            datax = 0;
            dataz = 1;
            lk.unlock();
            while (dataz)
                cv.notify_one();
        }
    } while (1);
}

void T2(const int& z)
{
    do {
        unique_lock<mutex> lk(m);
        cv.wait(lk, [] {return (dataz+kill); });
        if (kill) return;
        if (dataz) {
            cout << "z = " << z << endl;
            dataz = 0;
            zPrinted = 1;
            lk.unlock();
            while (zPrinted)
                cv.notify_one();
        }
    } while (1);
}

int main()
{
    int x, z;
    char c;
    thread threadT1(T1, cref(x), ref(z));
    thread threadT2(T2, cref(z));
    do {
        {
        unique_lock<mutex> lk(m);
        cout << "Enter x: ";
        cin >> x;
        datax = 1;
        lk.unlock();
        while (datax) 
            cv.notify_one();
        }
        {
        unique_lock<mutex> lk(m);
        cv.wait(lk, [] {return zPrinted; });
        lk.unlock();
        }
        zPrinted = 0;
        cout << "Continue? (y/n): ";
        cin >> c;
    } while (c == 'y');
    kill = 1;
    cv.notify_all();
    threadT1.join();
    threadT2.join();
    return 0;
}

Как вы видите, я ввел новую переменную "kill", которая при значении 1 заставляет оба потока выходить из своих бесконечных циклов, так чтозатем они могут быть объединены.

0 голосов
/ 30 мая 2018

Проблема заключается в следующем:

lk.unlock();
while (datax) {
  cv.notify_one();
}
cv.wait(lk, [] {return zPrinted; }); // <-- waiting on unlocked mutex
zPrinted = 0;

Вы ожидаете на разблокированном мьютексе с неопределенным поведением см. Здесь в примечаниях .

...