std :: condition_variable работает только во время отладки? - PullRequest
0 голосов
/ 31 мая 2018

Я написал проект на C ++ 14, скомпилированный с Intel ICPC на Fedora 26 (зависимость от 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. У кого-нибудь есть какие-либо советы о том, как действовать?

1 Ответ

0 голосов
/ 31 мая 2018

Если _terminate установлено после _terminate.load(std::memory_order_relaxed), но до std::unique_lock<std::mutex> acctLock(acctMutex);, _dataConditionVar.wait(acctLock) может блокироваться навсегда.

Вы не хотите использовать std::atomic с std::mutex и std::condition_variable, потому что такое использование часто приводит именно к этому состоянию гонки.Обычно вы используете std::atomic или std::mutex/std::condition_variable.

. Правильное использование: _terminate plain 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);
}
...