不理解条件变量超时

condition variable timeout not understood

我正在尝试给线程超时。 我尝试使用 std::condition_variable::wait_for,但这与我预期的不同。

这里是我的简单代码:

#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();
}

我希望线程 T1 休眠 10 秒。由于我在主线程中为 wait_for 设置了 1 秒超时,因此我希望 aftert1 end 之前打印。

相反,t1 运行了 10 秒(打印 t1 end),在打印 after 后仅 1 秒。

你能解释一下为什么它会这样吗?我应该怎么做才能让我的超时执行超时?

这与condition_variable无关。在 10 秒睡眠之前,您在 waitSec 中有一个 unique_lock,因此没有人能够在 10 秒内获得互斥锁,所以这一行:

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

将等到 waitSec 结束并由 unique_lock 析构函数释放 mutex

您需要在任何其他线程锁定您的互斥量之前创建您的 condition_variable

在这种情况下您不需要使用条件变量,因为您在 t1 启动后只在主线程中休眠 1 秒。

您在线程 1 中锁定互斥锁的实际情况是:

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

然后在主线程中你试图再次锁定这个互斥量(在 return 从 1 秒睡眠之后):

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

主线程只有在t1结束后才能获得这个锁(~9秒,共10秒)。然后程序会打印"before",成功获取锁后会等待任何事件1秒,因为:

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

并且没有人可以从等待中唤醒(通知)主线程,所以它只会平静地休眠 1 秒,然后打印 "after"

如此有效,您只需从线程函数中移除互斥锁定即可获得您想要的结果。由于您的主题不 interacting/share 相互资源

如果您需要等待一秒钟或直到线程完成,您可以这样做(请注意,这段代码并不理想,只是为了展示基本思想):

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;
}

发生这种情况是因为您的互斥量被锁定,而不是因为条件变量。

在 main() 中,您尝试在此处的第 1 行中获取互斥量:

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

但是您的线程 t1 在这里持有互斥量:

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

因此,在 t1 线程 waitSec 函数 运行 中的互斥锁被释放之前,main() 中的代码无法继续执行,这发生在函数结束时。

睡觉时不要持有互斥体。