繁体   English   中英

std :: unique_lock和std :: condition_variable如何工作

[英]How do std::unique_lock and std::condition_variable work

我需要弄清楚lock和condition_variable是如何工作的。

在这里cminplusreference的-slightly modified-code中

std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;

void worker_thread()
{
    // Wait until main() sends data
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, []{return ready;});

    // after the wait, we own the lock.
    std::cout << "Worker thread is processing data\n";
    data += " after processing";

    // Send data back to main()
    processed = true;
    std::cout << "Worker thread signals data processing completed\n";

    // Manual unlocking is done before notifying, to avoid waking up
    // the waiting thread only to block again (see notify_one for details)
    lk.unlock();
    cv.notify_one();
}

int main()
{
    std::thread worker(worker_thread);
    std::this_thread::sleep_for(std::chrono::seconds(1));

    data = "Example data";
    // send data to the worker thread
    {
        std::lock_guard<std::mutex> lk(m);
        ready = true;
        std::cout << "main() signals data ready for processing\n";
    }
    cv.notify_one();

    // wait for the worker
    {
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, []{return processed;});
    }
    std::cout << "Back in main(), data = " << data << '\n';

    worker.join();
}

我感到困惑的是,如果worker_thread已经锁定它,主线程如何锁定互斥锁。

这个答案我看到,这是因为cv.wait 解锁了互斥锁。

但是现在我对此感到困惑:那么为什么我们需要锁定它,如果cv.wait会解锁它?

例如,我可以这样做吗?

std::unique_lock<std::mutex> lk(m, std::defer_lock);

所以,我创建了锁对象,因为cv需要它,但是当我创建时我没有锁定它。

现在有什么不同吗?

我不明白为什么我收到“运行时错误” 这里在这种情况下。

引用自std :: condition_variable :: wait()

如果lock.mutex()未被当前线程锁定,则调用此函数是未定义的行为。

我将尝试为WHY条件变量需要锁定添加更多解释。

您必须拥有锁,因为您的代码需要检查条件谓词是否为真。 谓词是某些值或值的组合,为了继续,必须为真。 它可以是一个NULL指针或指向已准备好使用的已完成数据结构。

您必须在等待之前锁定它并检查谓词,因为在您开始等待条件时,另一个线程可能已经设置了它。

条件通知和等待返回并不意味着条件为真。 它只意味着条件在某个时候是真的。 它甚至可能是真的,然后是假的,然后又是真的。 这也可能意味着你的线程已经在一个不相关的信号处理程序中导致条件等待突破。 您的代码甚至不知道调用条件通知的次数。

所以一旦条件等待返回它就锁定互斥锁。 现在,您的代码可以安全地在锁中检查条件。 如果为true,则代码可以更新更新所需的内容并释放锁定。 如果不是这样,它只是回到条件等待再试一次。 例如,它可以采用该数据结构指针并将其复制到向量中,然后将锁保护指针设置回NULL。

将条件视为使轮询循环更有效的一种方法。 你的代码仍然必须完成它在循环等待中运行的所有事情,除了它可以进入休眠状态而不是不间断旋转。

我认为你的误解源于对锁是什么以及它们如何与条件变量相互作用的更深层次的误解。

锁存在的基本原因是提供互斥。 相互排除保证代码的某些部分仅由单个线程执行。 这就是为什么你不能等到锁定之后 - 你需要锁定以获得保证。

当您希望执行代码的某些其他部分但仍需要在当前代码执行时需要相互排除时,这会导致问题。 这是条件变量派上用场的地方:它们提供了一种结构化方式来释放锁定,并保证当你再次醒来时你会恢复它。 这就是在等待功能中解锁的原因。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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