gpt4 book ai didi

c++ - 程序关闭时 notify_all() 崩溃

转载 作者:行者123 更新时间:2023-11-28 04:23:39 27 4
gpt4 key购买 nike

我有一个非常简单的 C++ 程序,如下所示。 A、B 和 C 类位于 DLL 中。当我关闭这个应用程序时,它有时会在条件变量上调用 notify_all() 时崩溃。谁能告诉我原因吗?

我检查了很多关于 SO 的问答,但没有一个能解决我的问题。我在 Windows 7 和 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;
}

编辑 1: 如果我将 B 的析构函数中的代码放入不同的函数(例如 clean())并从 main() 调用它(使用 A 中的 clean() 方法)没有崩溃正在发生。

最佳答案

代码错过了条件变量通知,因为:

  1. stop_ = true 期间不持有互斥锁(它应该是 true,而不是 false)。 stop_ 必须在持有互斥量时读取和修改,它不需要是原子的。当人们将原子与互斥体和条件变量一起使用时,这是竞争条件的常见原因。
  2. 条件变量等待代码在等待前不检查条件。

修复:

class B;

class C
{
public:
C(const std::weak_ptr<B>& b) : mB(b) {}
~C() { stop(); }

void run()
{
while (true) {
std::unique_lock<std::mutex> uLock(mMutex);
while(!mStop /* && !other_real_condition */)
mCondition.wait_for(uLock, std::chrono::seconds(300));
if(mStop)
return;
// other_real_condition is true, process it.
}
}


void start()
{
mThread = std::thread(&C::run, this);
}

void stop()
{
{
std::unique_lock<std::mutex> uLock(mMutex);
mStop = true;
}
mCondition.notify_all();
if (mThread.joinable())
mThread.join();
}

private:
bool mStop = false; // <--- do not forget to initialize
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:

// basic methods
void init()
{
mC = std::unique_ptr<C>(new C(shared_from_this()));
mC->start();
}

private:
std::unique_ptr<C> mC;
};

如果你设置 mStop 而没有持有互斥锁,会发生以下情况:

| Thread 1              | Thread 2            |
| mStop = true | |
| mCondition.notify_all | |
| | mMutex.lock |
| | mCondition.wait_for |

尽管 mStop 已设置,但上面的线程 2 丢失了通知并等待。

更新共享状态时锁定互斥锁修复了竞争条件:

| Thread 1                | Thread 2               |
| mMutex.lock | |
| mStop = true | |
| mCondition.notify_all | |
| mMutex.unlock | |
| | mMutex.lock |
| | mStop == true, no wait |

当等待条件变量时,必须在持有互斥锁的同时修改和读取共享状态,否则条件通知会丢失并可能导致死锁(等待时没有超时)。这就是为什么不需要将原子与互斥锁和条件变量一起使用,您要么使用原子,要么使用互斥锁和条件变量,但不能同时使用两者。

关于c++ - 程序关闭时 notify_all() 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54929527/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com