Чтобы подождать определенное время или для определенного события, я бы использовал комбинацию std :: mutex и std :: condition_variable и, в частности, std :: condition_variable :: wait_for () в ожидании тайм-аута или сигнального изменения чего-либо.
Минимальный пример программы для демонстрации:
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
// a thread-shared flag to signal exit
std::atomic<bool> exitThread = false;
// a mutex to sync. inter-thread communication
std::mutex mtxAlert;
// a condition variable to signal changed data
std::condition_variable sigAlert;
// the data of inter-thread communication
bool alert = false;
void timerThread()
{
// the timeout for timer thread
auto timeout = 100ms;
// runtime loop
while (!exitThread) {
// lock mutex (preparation to wait in cond. var.)
std::unique_lock<std::mutex> lock(mtxAlert);
// unlock mutex and wait for timeout or signaled alert
sigAlert.wait_for(lock, timeout, []() { return alert || exitThread; });
// mutex is locked again
// check why wait_for() exited
if (exitThread) {
std::cout << "Timer thread exiting...\n";
return;
} else if (alert) {
std::cout << "Timer was interrupted due to alert.\n";
alert = false;
} else {
std::cout << "Timer achieved time-out.\n";
}
}
}
int main()
{
std::thread threadWait(&timerThread);
// wait a bit
std::cout << "main(): Waiting 300ms...\n";
std::this_thread::sleep_for(300ms);
// sim. interrupt
std::cout << "main(): Sim. interrupt.\n";
{ std::lock_guard<std::mutex> lock(mtxAlert);
alert = true;
}
sigAlert.notify_all();
// wait a bit
std::cout << "main(): Waiting 50 ms...\n";
std::this_thread::sleep_for(50ms);
// sim. interrupt
std::cout << "main(): Sim. interrupt.\n";
{ std::lock_guard<std::mutex> lock(mtxAlert);
alert = true;
}
sigAlert.notify_all();
// wait a bit
std::cout << "main(): Waiting 50 ms...\n";
std::this_thread::sleep_for(50ms);
// exiting application
exitThread = true;
sigAlert.notify_all();
threadWait.join();
// done
std::cout << "Done.\n";
}
Вывод:
main(): Waiting 300ms...
Timer achieved time-out.
Timer achieved time-out.
main(): Sim. interrupt.
main(): Waiting 50 ms...
Timer was interrupted due to alert.
main(): Sim. interrupt.
main(): Waiting 50 ms...
Timer was interrupted due to alert.
Timer thread exiting...
Done.
Живая демонстрация на coliru
OP заявил, что этот пример не скомпилирован должным образом на cygwin . Я попытался на своей стороне и могу подтвердить некоторые незначительные проблемы, которые я исправил:
Отсутствует #include <mutex>
добавлено
Инициализация std::atomic<bool> exitThread = false;
изменена на
std::atomic<bool> exitThread(false);
Я получил это, когда скомпилировал с g++
, а также с g++ -std=c++14
. (Кажется, что -std=c++14
является значением по умолчанию для моего g++
.)
Когда я использую g++ -std=c++17
, я не получаю никаких жалоб. Я твердо верю, что это как-то связано с copy-elision , которое g++
применимо к -std=c++17
, но не ранее.
Однако Это мой пример сеанса со слегка рассмотренным кодом на моем Windows 10 ноутбуке в cygwin64 :
$ g++ --version
g++ (GCC) 7.4.0
$
$ cat >testCondVar.cc <<'EOF'
> #include <atomic>
> #include <condition_variable>
> #include <iostream>
> #include <mutex>
> #include <thread>
> #include <chrono>
> using namespace std::chrono_literals;
>
> // a thread-shared flag to signal exit
> std::atomic<bool> exitThread(false);
>
> // a mutex to sync. inter-thread communication
> std::mutex mtxAlert;
> // a condition variable to signal changed data
> std::condition_variable sigAlert;
> // the data of inter-thread communication
> bool alert = false;
>
> void timerThread()
> {
> // the timeout for timer thread
> auto timeout = 100ms;
> // runtime loop
> while (!exitThread) {
> // lock mutex (preparation to wait in cond. var.)
> std::unique_lock<std::mutex> lock(mtxAlert);
> // unlock mutex and wait for timeout or signaled alert
> sigAlert.wait_for(lock, timeout, []() { return alert || exitThread; });
> // mutex is locked again
> // check why wait_for() exited
> if (exitThread) {
> std::cout << "Timer thread exiting...\n";
> return;
> } else if (alert) {
> std::cout << "Timer was interrupted due to alert.\n";
> alert = false;
> } else {
> std::cout << "Timer achieved time-out.\n";
> }
> }
> }
>
> int main()
> {
> std::thread threadWait(&timerThread);
> // wait a bit
> std::cout << "main(): Waiting 300ms...\n";
> std::this_thread::sleep_for(300ms);
> // sim. interrupt
> std::cout << "main(): Sim. interrupt.\n";
> { std::lock_guard<std::mutex> lock(mtxAlert);
> alert = true;
> }
> sigAlert.notify_all();
> // wait a bit
> std::cout << "main(): Waiting 50 ms...\n";
> std::this_thread::sleep_for(50ms);
> // sim. interrupt
> std::cout << "main(): Sim. interrupt.\n";
> { std::lock_guard<std::mutex> lock(mtxAlert);
> alert = true;
> }
> sigAlert.notify_all();
> // wait a bit
> std::cout << "main(): Waiting 50 ms...\n";
> std::this_thread::sleep_for(50ms);
> // exiting application
> exitThread = true;
> sigAlert.notify_all();
> threadWait.join();
> // done
> std::cout << "Done.\n";
> }
> EOF
$
Скомпилировано и запущено:
$ g++ -std=c++14 -o testCondVar testCondVar.cc
$ ./testCondVar
main(): Waiting 300ms...
Timer achieved time-out.
Timer achieved time-out.
main(): Sim. interrupt.
main(): Waiting 50 ms...
Timer was interrupted due to alert.
main(): Sim. interrupt.
main(): Waiting 50 ms...
Timer was interrupted due to alert.
Timer thread exiting...
Done.
$
Примечание:
Единственная причина, по которой для этого образца требуется минимум C ++ 14, - это использование std: : chrono_literals , что позволяет использовать, например, 300ms
.
Без std::chrono_literals
, это можно записать как std::chrono::milliseconds(300)
(что, по общему признанию, менее удобно). Заменив все std::chrono_literals
соответственно, я смог скомпилировать и запустить образец также с -std=c++11
.