Could two condition_variable.wait_for used with a single lock?

56 Views Asked by At

If codes like

std::mutex mut;
std::condition_variable cond;
bool is_ok = false;

void func() {
    std::unique_lock<std::mutex> lck(mut);
    if (!cond.wait_for(lck,
                        std::chrono::seconds(3),
                        [&] { return is_ok; })) {
        std::cout << "wait 1" << std::endl;
    }
    std::cout << "ok 1" << std::endl;
    if (!cond.wait_for(lck,
                        std::chrono::seconds(8),
                        [&] { return is_ok; })) {
        std::cout << "wait 2" << std::endl;
    }
    std::cout << "ok 2" << std::endl;
}

int main(){
    std::thread t(func);
    std::this_thread::sleep_for(std::chrono::seconds(1));
    {
        std::lock_guard<std::mutex> lck(mut);
        is_ok = true;
    }
    std::this_thread::sleep_for(std::chrono::seconds(10));
    if (t.joinable()){
        t.join();
    }    
}

As show https://godbolt.org/

Then what is the running sequence between thread t and main thread? Are both cond.wait_for valid?

In addition, the program ends with some error

Killed - processing time exceeded
Program terminated with signal: SIGKILL

Where does it come?

2

There are 2 best solutions below

2
Sebastian Redl On

Yes, you can of course wait_for a condition variable multiple times in its lifetime, and you can reuse the same lock object.

But you seem to misunderstand how condition variables work, because you never signal the one you have (by calling notify_one or notify_all from the main thread). So your wait attempts just time out.

And since godbolt limits your program's execution wall time to far less than the 11 seconds you sleep for in total, your job just gets killed. You should do tests like this on your local computer.

0
stefaanv On

Yes, how else would you wait for a change in condition in a loop?

To correct the code, reset the is_ok when the first wait in func() is done and set is_ok and notify twice (in a loop) in main() since you wait twice.