Сценарий:
У меня есть механизм ожидания и сигнала на основе condition_variable . Это работает! Но мне нужно немного больше, чем просто механизм ожидания и сигнала класса c. Я должен быть в состоянии сделать синхронизированное ожидание так же как бесконечное ожидание "на том же самом condition_variable
". Поэтому я создал класс-оболочку вокруг condition_variable
, который также решает проблему ложного пробуждения. Ниже приведен код для этого:
Код:
// CondVarWrapper.hpp
#pragma once
#include <mutex>
#include <chrono>
#include <condition_variable>
class CondVarWrapper {
public:
void Signal() {
std::unique_lock<std::mutex> unique_lock(cv_mutex);
cond_var_signalled = true;
timed_out = false;
unique_lock.unlock();
cond_var.notify_one();
}
bool WaitFor(const std::chrono::seconds timeout) {
std::unique_lock<std::mutex> unique_lock(cv_mutex);
timed_out = true;
cond_var.wait_for(unique_lock, timeout, [this] {
return cond_var_signalled;
});
cond_var_signalled = false;
return (timed_out == false);
}
bool Wait() {
std::unique_lock<std::mutex> unique_lock(cv_mutex);
timed_out = true;
cond_var.wait(unique_lock, [this] {
return cond_var_signalled;
});
cond_var_signalled = false;
return (timed_out == false);
}
private:
bool cond_var_signalled = false;
bool timed_out = false;
std::mutex cv_mutex;
std::condition_variable cond_var;
};
// main.cpp
#include "CondVarWrapper.hpp"
#include <iostream>
#include <string>
#include <thread>
int main() {
CondVarWrapper cond_var_wrapper;
std::thread my_thread = std::thread([&cond_var_wrapper]{
std::cout << "Thread started" << std::endl;
if (cond_var_wrapper.WaitFor(std::chrono::seconds(10))) {
std::cout << "Thread stopped by signal from main" << std::endl;
} else {
std::cout << "ERROR: Thread stopping because of timeout" << std::endl;
}
});
std::this_thread::sleep_for(std::chrono::seconds(3));
// Uncomment following line to see the timeout working
cond_var_wrapper.Signal();
my_thread.join();
}
Вопрос:
Над кодом хорошо, но я думаю, что есть одна проблема? Могу ли я действительно сделать wait
, а также wait_for
на том же condition_variable
? Что, если поток получил cv_mutex
, вызвав CondVarWrapper::Wait()
, и этот по какой-то причине никогда не вернулся. И затем появляется другой поток, вызывающий CondVarWrapper::WaitFor(std::chrono::seconds(3))
, ожидающий возврата, если он не преуспеет в течение 3 секунд. Теперь этот второй поток не сможет вернуться из WaitFor
через 3 секунды, не так ли? На самом деле это никогда не вернется. Потому что ожидание condition_variable
- это время ожидания, а не блокировка cv_mutex
. Я прав или я не прав в этом понимании?
Если я прав выше, мне нужно заменить std::mutex cv_mutex
на std::timed_mutex cv_mutex
, выполнить timed_wait в CondVarWrapper::WaitFor
и сделать бесконечное ожидание CondVarWrapper::Wait
? Или есть ли лучшие / более простые способы справиться с этим?