std::condition_variable 只在调试时有效?

std::condition_variable only works while debugging?

我用 C++14 写了一个项目,在 Fedora 26 上用 Intel 的 icpc 编译(依赖 gcc 7)。一切都很好并且工作正常,直到我将我的项目转移到 Centos 7 上,并开始遇到非常神秘的行为。

在Centos上(scl enable devtoolset-7 bash),源代码编译链接没有错误,但是项目只有在用GDB调试时才能运行。如果不调试,条件变量唤醒休眠线程的通知不会起作用。

多个工作线程进入休眠状态,但通知不起作用,也没有唤醒。但是 运行 GDB,一切正常。

我禁用了所有优化。我尝试静态链接 libstdc++ 和 libgcc,但没有任何效果。我尝试了一个小测试程序,condition_variable 工作正常。我还测试了 Fedora 27,它解决了这个问题。

这是一个例子:

    // worker thread
    // term and cv passed in with std::ref()
    std::atomic<bool> &_terminate = term;
    std::condition_variable &_dataConditionVar = cv;
    std::mutex acctMutex;

    while (!_terminate.load(std::memory_order_relaxed)) {
        // do stuff here ....

        // wait for notification
        std::unique_lock<std::mutex> acctLock(acctMutex);
        _dataConditionVar.wait(acctLock);   // Thread never wakes up <<
    }

适用于 Fedora 26/27,但不适用于 Centos 7。有人对如何进行有任何建议吗?

如果_terminate设置在_terminate.load(std::memory_order_relaxed)之后但在std::unique_lock<std::mutex> acctLock(acctMutex);之前,_dataConditionVar.wait(acctLock)可能会永远阻塞。

您不想将 std::atomicstd::mutexstd::condition_variable 一起使用,因为这种用法通常会导致这种竞争条件。通常,您使用 std::atomicstd::mutex/std::condition_variable.

正确的用法是使 _terminate 普通 bool 并仅在持有互斥锁时访问它:

bool _terminate = false;
std::condition_variable _dataConditionVar;
std::mutex acctMutex;

// Set _terminate example.
{
    std::unique_lock<std::mutex> acctLock(acctMutex);
    _terminate = true;
    _dataConditionVar.notify_one();
}

// Wait for _terminate to be set example.
{
    std::unique_lock<std::mutex> acctLock(acctMutex);
    while(!_terminate)
        _dataConditionVar.wait(acctLock);
}