简体   繁体   中英

condition variable timeout not understood

I am playing to try to give a timeout to a thread. I try to use std::condition_variable::wait_for but this behaves differently than I would expect.

Here my simple code:

#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
#include <condition_variable>

std::mutex myMutex;

void waitSec(int seconds)
{
    std::cout <<"t1 start" <<std::endl;
    std::unique_lock<std::mutex> lock(myMutex);
    std::this_thread::sleep_for(std::chrono::seconds(seconds));
    std::cout <<"t1 end" <<std::endl;
}

int main(void)
{
    // launch thread that sleeps 10s
    std::thread t1(waitSec,10);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    // wait for lock during max 1 second
    std::condition_variable* conditionVariable = new std::condition_variable();
    std::cout << "before" << std::endl;
    std::unique_lock<std::mutex> lock(myMutex);
    conditionVariable->wait_for(lock,std::chrono::seconds(1));
    std::cout << "after" << std::endl;

    t1.join();
}

I expect Thread T1 to sleeps for 10 seconds. Since I give 1s timeout to the wait_for in the main thread I would expect that after is printed before t1 end .

What happens instead is that t1 runs for 10 seconds, (printing t1 end ) and just 1s after after is printed.

Can you explain me why it behaves like this and what should I do to get my timeout performing as a timeout?

This has nothing to do with condition_variable . You have a unique_lock in waitSec before your 10 seconds sleep so no one will be able to acquire the mutex for 10 seconds so this line:

std::unique_lock<std::mutex> lock(myMutex);

Will wait until the end of waitSec and the release of mutex by the unique_lock destructor.

You need to create your condition_variable before any other thread locked your mutex.

You don't need to use conditional variables in this case, as you just sleep 1 second in the main thread after t1 start.

What is actually happened that you have locked the mutex in the thread 1:

std::unique_lock<std::mutex> lock(myMutex);

then in the main thread you are trying to lock this mutex again (after the return from 1 second sleep):

std::cout << "before" << std::endl;
std::unique_lock<std::mutex> lock(myMutex);

The main thread will able to obtain this lock only after t1 will be finished (~9 seconds, total 10 sesconds). Then the program will print "before" and successfully obtain lock and will wait for any event for 1 second, because:

conditionVariable->wait_for(lock,std::chrono::seconds(1));

And there is nobody can wake (notify) the main thread from the waiting, so it will just calmly sleep for 1 second and then prints "after"

So effectively you can get what do you want just removing mutex locking from the thread function. As your threads not interacting/share resourses with each-other

If you need to wait was one second or until thread is finished you can do something like this (please note that this code not ideal, just to show the basic idea):

std::condition_variable cv;

void worker_thread()
{
    // do something
    // ...
    cv.notify_one();
}

int main() {
   std::thread t1(worker_thread);

   std::cout << "before" << std::endl;
   std::unique_lock<std::mutex> lock(myMutex);
   cv.wait_for(lock,std::chrono::seconds(1));
   std::cout << "after" << std::endl;
}

This happens because your mutex is locked, not because of the condition variable.

in main() you try to acquire the mutex in the 1 line here:

std::unique_lock<std::mutex> lock(myMutex);
conditionVariable->wait_for(lock,std::chrono::seconds(1));

However your thread t1 holds the mutex here:

std::unique_lock<std::mutex> lock(myMutex);
std::this_thread::sleep_for(std::chrono::seconds(seconds));

Thus the code in main() cannot proceed until the mutex in the waitSec function run by the t1 thread is released, which happens when the function ends.

Don't hold mutexes while sleeping.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM