Waiting for an atomic_bool

10,523

Solution 1

With the help of cbreak and Ravadre (comments) I got from here:

int main()
{
    std::mutex m;
    std::condition_variable cv;

    std::thread t([&] {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            std::unique_lock<std::mutex> lock(m);
            cv.wait(lock);
            std::cout << "Yay!\n";
    });

    cv.notify_one();
    t.join();
}

Which does not usually terminate at all, to here:

int main()
{
    std::mutex m;
    std::condition_variable cv;
    bool flag = false;

    std::thread t([&] {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::unique_lock<std::mutex> lock(m);
        cv.wait(lock, [&] { return flag; });
        std::cout << "Yay!\n";
    });

    {
        std::lock_guard<std::mutex> lock(m);
        flag = true;
    }

    cv.notify_one();
    t.join();
}

Which actually does the job, but still seems like a lot of unnecessary overhead. Feel free to post an equivalent but more performant (or more elegant) answer, I'll happily accept it. Please do only use standard-C++11 though, and if not, explain why standard-C++11 cannot do this.

Edit: I also wrote a class safe_flag to encapsulate this (thanks again to cbreak); feel free to suggest any improvements.

class safe_flag
{
    mutable std::mutex m_;
    mutable std::condition_variable cv_;
    bool flag_;

public:
    safe_flag()
        : flag_(false)
    {}

    bool is_set() const
    {
        std::lock_guard<std::mutex> lock(m_);
        return flag_;
    }

    void set()
    {
        {
            std::lock_guard<std::mutex> lock(m_);
            flag_ = true;
        }
        cv_.notify_all();
    }

    void reset()
    {
        {
            std::lock_guard<std::mutex> lock(m_);
            flag_ = false;
        }
        cv_.notify_all();
    }

    void wait() const
    {
        std::unique_lock<std::mutex> lock(m_);
        cv_.wait(lock, [this] { return flag_; });
    }

    template <typename Rep, typename Period>
    bool wait_for(const std::chrono::duration<Rep, Period>& rel_time) const
    {
        std::unique_lock<std::mutex> lock(m_);
        return cv_.wait_for(lock, rel_time, [this] { return flag_; });
    }

    template <typename Rep, typename Period>
    bool wait_until(const std::chrono::duration<Rep, Period>& rel_time) const
    {
        std::unique_lock<std::mutex> lock(m_);
        return cv_.wait_until(lock, rel_time, [this] { return flag_; });
    }
};

Solution 2

bool go = false;
std::mutex mtx;
std::condition_variable cnd;

// waiting thread:
std::unique_lock<std::mutex> lck(mtx);
while (!go)
    cnd.wait(lock);
// when we get here we know that go is true, and we have the lock

// signalling thread:
{
std::unique_lock<std::mutex> lck(mtx);
go = true;
cnd.notify_one();
}
// now we've released the lock, so the waiting thread will make progress

Solution 3

What exactly is your platform? On posix-compliant platforms we use

  sem_t semaphore;
  sem_init( &semaphore , 0 , x );

to get a semaphore with initial value of x. Then with

 sem_wait(&semaphore ); sem_post(&semaphore);

you can synchronize the two threads. Remember to declare semaphore as a global variable to make sure both threads can access it (or by any other means that achieve the same).

So long story short, you can:

sem_t semaphore;
sem_init(&semaphore, 0 , 0 );
void thread2(){
   sem_post(&semaphore);    //second thread --A
}
void thread1(){
    sem_wait(&semaphore);   // wait until thread2() executes line A
}

There should be similar utilities to achieve the same on Win32 too.

Share:
10,523
cooky451
Author by

cooky451

GitHub: https://github.com/cooky451

Updated on July 24, 2022

Comments

  • cooky451
    cooky451 almost 2 years

    I have two threads and a flag that gets set by the second thread. I could use an atomic_bool, but I want to be able to wait* for the flag being set on the first thread. How can I do that?

    I can't use a condition_variable I guess, because if the second thread calls notify_one before the first thread starts waiting, the thread won't wake up.

    Also, checking if the flag has already been set should be reasonably fast. I guess this should be rather simple, but I'm just stuck, so I'm asking here. Thanks in advance.

    *Edit: Block of course, not busy-wait. Sorry if that wasn't clear.

  • cooky451
    cooky451 over 11 years
    How is that really different from my answer? :)
  • Pete Becker
    Pete Becker over 11 years
    @cooky451 - the loop is explicit here, making it clearer to beginners what's going on.
  • Jonathan Wakely
    Jonathan Wakely over 11 years
    Not only explicit, but the syntax of while (!go) is simpler (and less typing) than a lambda expression that does nothing but return a bool