Search code examples
c++multithreadinglockingmutexcondition-variable

Issue with lock and condition variable in c++ multithreading


I'm trying to implement a simple example of multithreading in C++ (Windows 10, Visual Studio Express).

I have thread T1 that calculates z = x * x, where x and z are global variables. Thread T2 displays z.

I wanted to use locks and a condition variable.

For some reason the execution gets stuck while T1 un unblocked (after cv.wait, probably in the while loop -- high CPU usage). But this does not occur when I add some code (I tried with cout << "x" << endl;) before the cv.notify_one(); in main(). It's very strange.

Thank you in advance for your help!

Here is the code. I removed the parts I put to kill the threads because I do not get to that part of the algorithm -- the issue is before.

#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;
}

Solution

  • The problem lies here:

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

    You are waiting on an unlocked mutex and is undefined behaviour see here under notes.