如何使用condition_variable真正wait_for不超过一定的持续时间

问题描述 投票:13回答:3

作为it turns outcondition_variable::wait_for应该被称为condition_variable::wait_for_or_possibly_indefinitely_longer_than,因为它需要在真正超时和返回之前重新获取锁定。

请参阅this program进行演示。

有没有办法表达,“看,我真的只有两秒钟。如果myPredicate()当时仍然是假的和/或锁仍然被锁定,我不在乎,只是随便继续,并给我一个方法发现那个。“

就像是:

bool myPredicate();
auto sec = std::chrono::seconds(1);

bool pred;
std::condition_variable::cv_status timedOut;

std::tie( pred, timedOut ) =
    cv.really_wait_for_no_longer_than( lck, 2*sec, myPredicate );

if( lck.owns_lock() ) {
    // Can use mutexed resource.
    // ...
    lck.unlock();
} else {
    // Cannot use mutexed resource. Deal with it.
};
c++ multithreading c++11 condition-variable
3个回答
7
投票

我认为你误用了condition_variable的锁。它仅用于保护条件,而不是用于保护耗时的工作。

你可以通过将mutex分成两个来轻松修复你的例子 - 一个用于临界区,另一个用于保护ready条件的修改。这是修改后的片段:

typedef std::unique_lock<std::mutex> lock_type;
auto sec = std::chrono::seconds(1);
std::mutex mtx_work;
std::mutex mtx_ready;
std::condition_variable cv;
bool ready = false;

void task1() {
    log("Starting task 1. Waiting on cv for 2 secs.");
    lock_type lck(mtx_ready);
    bool done = cv.wait_for(lck, 2*sec, []{log("Checking condition..."); return ready;});
    std::stringstream ss;
    ss << "Task 1 finished, done==" << (done?"true":"false") << ", " << (lck.owns_lock()?"lock owned":"lock not owned");
    log(ss.str());
}

void task2() {
    // Allow task1 to go first
    std::this_thread::sleep_for(1*sec);
    log("Starting task 2. Locking and sleeping 2 secs.");
    lock_type lck1(mtx_work);
    std::this_thread::sleep_for(2*sec);
    lock_type lck2(mtx_ready);
    ready = true; // This happens around 3s into the program
    log("OK, task 2 unlocking...");
    lck2.unlock();
    cv.notify_one();
}

它的输出:

@2 ms: Starting task 1. Waiting on cv for 2 secs.
@2 ms: Checking condition...
@1002 ms: Starting task 2. Locking and sleeping 2 secs.
@2002 ms: Checking condition...
@2002 ms: Task 1 finished, done==false, lock owned
@3002 ms: OK, task 2 unlocking...

0
投票

实际上,condition_variable::wait_for完全符合您的要求。您的示例的问题是您锁定了2秒的睡眠以及ready = true赋值,使得条件变量甚至无法在达到时间限制之前评估谓词。

std::this_thread::sleep_for(2*sec);线放在锁外,亲自看看。


0
投票

有没有办法表达,“看,我真的只有两秒钟。如果myPredicate()当时仍然是假的和/或锁仍然锁定,我不在乎,只要继续,不管......”

是的,有一种方法,但不幸的是,在wait_for的情况下,它必须是手动的。由于wait_forSpurious Wakeup无限期等待。想象你的循环如下:

while(!myPredicate())
  cv.wait_for(lock, std::chrono::duration::seconds(2);

虚假唤醒可以在任意平台中随时发生。想象一下,在你的情况下它发生在200毫秒内。因此,没有任何外部通知,wait_for()将在循环条件下唤醒并检查myPredicate()

正如预期的那样,条件将是假的,因此循环将为真,并且它将再次执行cv.wait_for(..),新鲜的2秒。这就是无限运行的方式。

您可以自己控制更新持续时间,也可以使用最终在wait_until()中调用的wait_for()

© www.soinside.com 2019 - 2024. All rights reserved.