std :: condition_variable не правильно просыпается после std :: condition_variable :: notify_all () из другого потока

Этот код является упрощением реального кода проекта. Основной поток создает рабочий поток и ожидает с std :: condition_variable, чтобы рабочий поток действительно запустился. В приведенном ниже коде std :: condition_variable активируется после того, как current_thread_state становится «ThreadState :: Stopping» — это второе уведомление от рабочего потока, то есть основной поток не проснулся после первого уведомления, когда current_thread_state становится «ThreadState :: Starting» ». Результат оказался в тупике. Почему это происходит? Почему std :: condition_variable не просыпается после первого thread_event.notify_all ()?

int main()
{
std::thread thread_var;
struct ThreadState {
enum Type { Stopped, Started, Stopping };
};
ThreadState::Type current_thread_state = ThreadState::Stopped;
std::mutex thread_mutex;
std::condition_variable thread_event;
while (true) {
{
std::unique_lock<std::mutex> lck(thread_mutex);
thread_var = std::move(std::thread([&]() {
{
std::unique_lock<std::mutex> lck(thread_mutex);
cout << "ThreadFunction() - step 1\n";
current_thread_state = ThreadState::Started;
}
thread_event.notify_all();

// This code need to disable output to console (simulate some work).
cout.setstate(std::ios::failbit);
cout << "ThreadFunction() - step 1 -> step 2\n";
cout.clear();

{
std::unique_lock<std::mutex> lck(thread_mutex);
cout << "ThreadFunction() - step 2\n";
current_thread_state = ThreadState::Stopping;
}
thread_event.notify_all();
}));

while (current_thread_state != ThreadState::Started) {
thread_event.wait(lck);
}
}

if (thread_var.joinable()) {
thread_var.join();
current_thread_state = ThreadState::Stopped;
}
}
return 0;
}

0

Решение

Как только вы позвоните notify_all метод, ваш основной поток и ваш рабочий поток (после выполнения своей работы) пытаются получить блокировку на thread_mutex мьютекс. Если ваша рабочая нагрузка незначительна, как в вашем примере, рабочий поток, скорее всего, получит блокировку перед основным потоком и вернет состояние обратно ThreadState::Stopped прежде чем основной поток когда-либо читает его. Это приводит к мертвой блокировке.

Попробуйте добавить значительную рабочую нагрузку, например,

std::this_thread::sleep_for( std::chrono::seconds( 1 ) );

на рабочий поток. Мертвые замки теперь гораздо менее вероятны. Конечно, это не решение вашей проблемы. Это просто для иллюстрации проблемы.

2

Другие решения

У вас есть две темы: одна записывает значения current_thread_state дважды, другой читает значение current_thread_state один раз.

Неясно, является ли последовательность событий запись-запись-чтение или запись-чтение-запись, как вы ожидаете, оба являются допустимыми выполнениями вашего приложения.

0

По вопросам рекламы [email protected]