Error when exiting a program using `std::condition_variable`

96 Views Asked by At

I've a problem with some code with the same logic of the following one:

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

int main() {
  std::condition_variable myCV;
  std::mutex myMutex;
  std::unique_lock myLock(myMutex);
  bool isRunning{ true };

  std::jthread myThread([&isRunning, &myCV, &myLock]() {
    while (isRunning) {
      myCV.wait(myLock);
      // do some work here
    }
    std::cout << "Exited from myThread while loop." << std::endl;
    });

  for (int i = 0; i < 100; i++) {
    myCV.notify_one();
    std::this_thread::sleep_for(std::chrono::milliseconds(20));
    std::cout << "Test loop " << i << std::endl;
  }

  isRunning = false;
  myCV.notify_one();

  return 0;
}

Basically, I've a loop where i do some work, and when my work is done at every iteration I call a method in another thread for handling the data without blocking the main thread; in order to avoid to create and destruct the thread every time, I'm using a loop inside that thread with a std::condition_variable for starting to manage the data when they are ready.

The logic works well but I've a problem when exiting the program; if I run the code I've an error when the program ends, because the mutex destructor calls abort():

...\stl\src\mutex.cpp(164): unlock of unowned mutex

If I comment the following row myCV.notify_one(); the program continues to run without stopping.

How can I exit the program gracefully without any error? What I'm doing wrong?

1

There are 1 best solutions below

5
Jepessen On BEST ANSWER

Thanks for your comments. The problem was in fact the mutex that was unlocked in a thread different from the one that acquired it. Moving the lock definition inside the thread code solved the problem:

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

int main() {
  std::condition_variable myCV;
  std::mutex myMutex;
  bool isRunning{ true };

  std::jthread myThread([&isRunning, &myCV, &myMutex]() {
    std::unique_lock myLock(myMutex);
    while (isRunning) {
      myCV.wait(myLock);
      // do some work here
    }
    std::cout << "Exited from myThread while loop." << std::endl;
    });

  for (int i = 0; i < 100; i++) {
    myCV.notify_one();
    std::this_thread::sleep_for(std::chrono::milliseconds(20));
    std::cout << "Test loop " << i << std::endl;
  }

  isRunning = false;
  myCV.notify_one();

  return 0;
}