Search code examples
c++c++11mutexcondition-variablestdthread

How to wake a std::thread while it is sleeping


I am using C++11 and I have a std::thread which is a class member, and it sends information to listeners every 2 minutes. Other that that it just sleeps. So, I have made it sleep for 2 minutes, then send the required info, and then sleep for 2 minutes again.

// MyClass.hpp
class MyClass {

    ~MyClass();
    RunMyThread();

private:
    std::thread my_thread;
    std::atomic<bool> m_running;
}


MyClass::RunMyThread() {

    my_thread = std::thread { [this, m_running] {
    m_running = true;
    while(m_running) {
        std::this_thread::sleep_for(std::chrono::minutes(2));
        SendStatusInfo(some_info);
    }
}};
}

// Destructor
~MyClass::MyClass() {
    m_running = false; // this wont work as the thread is sleeping. How to exit thread here?
}

Issue:
The issue with this approach is that I cannot exit the thread while it is sleeping. I understand from reading that I can wake it using a std::condition_variable and exit gracefully? But I am struggling to find a simple example which does the bare minimum as required in above scenario. All the condition_variable examples I've found look too complex for what I am trying to do here.

Question:
How can I use a std::condition_variable to wake the thread and exit gracefully while it is sleeping? Or are there any other ways of achieving the same without the condition_variable technique?

Additionally, I see that I need to use a std::mutex in conjunction with std::condition_variable? Is that really necessary? Is it not possible to achieve the goal by adding the std::condition_variable logic only to required places in the code here?

Environment:
Linux and Unix with compilers gcc and clang.


Solution

  • A working example for you using std::condition_variable:

    struct MyClass {
        MyClass()
            : my_thread([this]() { this->thread(); })
        {}
    
        ~MyClass() {
            {
                std::lock_guard<std::mutex> l(m_);
                stop_ = true;
            }
            c_.notify_one();
            my_thread.join();
        }
    
        void thread() {
            while(this->wait_for(std::chrono::minutes(2)))
                SendStatusInfo(some_info);
        }
    
        // Returns false if stop_ == true.
        template<class Duration>
        bool wait_for(Duration duration) {
            std::unique_lock<std::mutex> l(m_);
            return !c_.wait_for(l, duration, [this]() { return stop_; });
        }
    
        std::condition_variable c_;
        std::mutex m_;
        bool stop_ = false;
        std::thread my_thread;
    };