#include <chrono>
#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
// a condition variable is (almost always used) in combination
// with a mutex and a value so wrap that concept once for reuse
// it is a template so you can also use it with enum values
// (very useful for communicating state changes!)
// or you can use integer type to use it as a semaphore too
template<typename type_t>
class synchronization_signal_t final
{
public:
explicit synchronization_signal_t(const type_t& value) :
m_value{ value }
{
}
~synchronization_signal_t() = default;
void operator=(const type_t& value)
{
std::unique_lock<std::mutex> lock{ m_mtx };
m_value = value;
m_signal.notify_all();
}
void wait_for(const type_t& value)
{
std::unique_lock<std::mutex> lock{ m_mtx };
// wait with predicate
m_signal.wait(lock, [&] { return m_value == value; });
}
private:
std::mutex m_mtx;
std::condition_variable m_signal;
type_t m_value;
};
// for readable time notation
using namespace std::chrono_literals;
int main()
{
// create a simple two state (bool) signal
synchronization_signal_t<bool> signal{ false };
// start a thread
std::thread thread1{ [&]
{
std::cout << "thread started\n";
std::this_thread::sleep_for(2s);
std::cout << "thread setting signal\n";
// set the signal
signal = true;
std::cout << "thread signal set\n";
}};
// the mainthread will wait for thread1 to have finished
std::cout << "mainthread waiting...\n";
signal.wait_for(true);
std::cout << "mainthread done waiting\n";
thread1.join();
return 0;
}