Прерываемый сон в std :: thread - PullRequest
0 голосов
/ 15 января 2020

У меня есть простая программа на C ++ 11, как показано ниже.

Код:

#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>

int main(int argc, char *argv[]) {

   std::cout << "My program starts" << std::endl;
   std::atomic<bool> exit_thread(false);
   std::thread my_thread = std::thread([&exit_thread]{
        do {
            std::cout << "Thread is doing something..." << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(5));
        } while (!exit_thread);
    });

   std::this_thread::sleep_for(std::chrono::seconds(12));
   exit_thread = true;
   std::cout << "Might have to wait to exit thread" << std::endl;
   my_thread.join();
   return 0;
}

Как вы можете видеть выше, есть все oop с sleep_for, который заставляет поток спать в течение 5 секунд, а затем снова просыпается и повторяет цикл при условии, что для exit_thread установлено значение false. Главный поток ожидает 12 секунд и сначала готовится к выходу, установив для exit_thread значение true, а затем выполняет join для потока. Все хорошо до сих пор.

Проблема:
Выше все в порядке и работает для цели. Но есть «потенциальная проблема». Если поток только что начал спать, ему потребуется еще 4 секунды, прежде чем он выйдет из режима сна, чтобы обнаружить, что теперь ему нужно выйти. Это задерживает процесс выхода и разрушения.

Вопрос:
Как сделать так, чтобы поток непрерывно спал? Так что я могу прервать сон и заставить поток сразу же выйти из него, отменив выход из сна, вместо того, чтобы ждать потенциальные 4, 3 или 2 секунды.

Я думаю, что решение этой проблемы может быть достигнуто с помощью std :: condition_variable ? Вероятно? Я ищу фрагмент кода, чтобы показать, как.

Обратите внимание , что мой код работает как на clang, так и на g cc.

1 Ответ

1 голос
/ 15 января 2020

Мы должны ждать условной переменной или семафора вместо сна. Вот минимальное изменение, чтобы сделать это:

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

int main()
{
   std::cout << "My program starts" << std::endl;
   std::atomic<bool> exit_thread(false);
   std::condition_variable cv;
   std::mutex m;

   std::thread my_thread = std::thread([&exit_thread,&cv,&m]{
        do {
            std::cout << "Thread is doing something..." << std::endl;
            {
                std::unique_lock<std::mutex> lock(m);
                cv.wait_for(lock, std::chrono::seconds(5));
            }
        } while (!exit_thread);
    });

   std::this_thread::sleep_for(std::chrono::seconds(12));
   {
       std::lock_guard<std::mutex> guard(m);
       exit_thread = true;
   }
   cv.notify_all();

   std::cout << "Thread stops immediately" << std::endl;
   my_thread.join();
}

Очевидно, нам нужен мьютекс:

Даже если общая переменная - это atomi c, она должна быть изменена в мьютекс, чтобы правильно опубликовать sh модификацию ожидающего потока.

...