Этот код является упрощением реального кода проекта. Основной поток создает рабочий поток и ожидает с 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;
}
Как только вы позвоните notify_all
метод, ваш основной поток и ваш рабочий поток (после выполнения своей работы) пытаются получить блокировку на thread_mutex
мьютекс. Если ваша рабочая нагрузка незначительна, как в вашем примере, рабочий поток, скорее всего, получит блокировку перед основным потоком и вернет состояние обратно ThreadState::Stopped
прежде чем основной поток когда-либо читает его. Это приводит к мертвой блокировке.
Попробуйте добавить значительную рабочую нагрузку, например,
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
на рабочий поток. Мертвые замки теперь гораздо менее вероятны. Конечно, это не решение вашей проблемы. Это просто для иллюстрации проблемы.
У вас есть две темы: одна записывает значения current_thread_state
дважды, другой читает значение current_thread_state
один раз.
Неясно, является ли последовательность событий запись-запись-чтение или запись-чтение-запись, как вы ожидаете, оба являются допустимыми выполнениями вашего приложения.