I have a very simple C++ program like below. The A, B and C classes are inside a DLL. When I close this application, it sometimes crashing while calling notify_all() on the condition variable. Can anybody give me a hint about the reason?
I have checked lots of Q/As on SO, but none of them solved my problem. I work on windows 7 and VS2013.
class B;
class C
{
public:
C(const std::weak_ptr<B>& b) : mB(b)
{
}
virtual ~C()
{
}
void run()
{
while (true)
{
std::unique_lock<std::mutex> uLock(mMutex);
// Wait until some event is happening
mCondition.wait_for(uLock, std::chrono::seconds(300));
if (!mStop)
{
//do something here
}
else
{
return;
}
}
}
void start()
{
mThread = std::thread(&C::run, this);
}
void stop()
{
mStop = false;
}
void notify()
{
mCondition.notify_all();
}
void join()
{
if (mThread.joinable())
{
mThread.join();
}
}
private:
std::atomic<bool> mStop;
std::condition_variable mCondition;
std::mutex mMutex;
std::thread mThread;
std::weak_ptr<B> mB;
};
class B : public std::enable_shared_from_this<B>
{
public:
B() {}
~B()
{
if (mC)
{
mC->stop();
mC->notify();
mC->join();
}
}
// basic methods
void init()
{
mC = std::unique_ptr<C>(new C(shared_from_this()));
mC->start();
}
private:
std::unique_ptr<C> mC;
};
class A
{
public:
~A(){}
void init() { pImpl->init(); }
static std::shared_ptr<A> getInstance(){
static std::shared_ptr<A> instance(new A);
return instance;
}
private:
A() : pImpl(std::make_shared<B>()){}
std::shared_ptr<B> pImpl;
};
void main()
{
std::shared_ptr<A> a = A::getInstance();
a->init();
int x;
std::cin >> x;
}
Edit 1: If I put the code in B's destructor in a different function (e.g. clean()) and call it from main() (using a clean() method in A) no crash is happening.
This seems to be a CRT bug (https://stackoverflow.com/a/50525968/896012). The problem does not happen on new versions of Windows, i.e. Windows 10. To fix the crash on Windows 7, I just removed the condition_variable and used a simple sleep instead and while exiting the program I just detached the thread. Although this is not a clean approach, but I think it is the only way to avoid the crash. If anyone found a better answer, just let me know.