为什么我需要std :: condition_variable? [英] why do I need std::condition_variable?

查看:80
本文介绍了为什么我需要std :: condition_variable?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现 std :: condition_variable 由于虚假唤醒而很难使用。因此有时候我需要设置一个标志,例如:

I found that std::condition_variable is very difficult to use due to spurious wakeups. So sometimes I need to set a flags such as:

atomic<bool> is_ready;

我将 is_ready 设置为 true 在我打电话通知之前( notify_one() notify_all()),然后我等待:

I set is_ready to true before I call notify (notify_one() or notify_all()), and then I wait:

some_condition_variable.wait(some_unique_lock, [&is_ready]{
    return bool(is_ready);
});

是否有任何我不应该这样做的理由:(编辑:好,这真的

Is there any reason that I shouldn't just do this: ( Ok, this is really a bad idea.)

while(!is_ready) {
    this_thread::wait_for(some_duration); //Edit: changed from this_thread::yield();
}

如果 condition_variable 选择了等待时间(我不知道这是否成立),我宁愿自己选择。

And if condition_variable had chosen a waiting duration (I don't know whether this is true or not), I prefer choose it myself.

推荐答案

您可以使用以下任何一种方式进行编码:

You can code this either way:


  1. 使用原子和轮询循环。

  2. 使用 condition_variable

  1. Using atomics and a polling loop.
  2. Using a condition_variable.

我在下面为您两种方式都进行了编码。在我的系统上,我可以实时监视任何给定进程使用了​​多少cpu。

I've coded it both ways for you below. On my system I can monitor in real time how much cpu any given process is using.

#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>

std::atomic<bool> is_ready(false);

void
test()
{
    std::this_thread::sleep_for(std::chrono::seconds(30));
    is_ready.store(true);
}

int
main()
{
    std::thread t(test);
    while (!is_ready.load())
        std::this_thread::yield();
    t.join();
}

对我来说这需要30秒才能执行,而执行该过程大约需要30秒cpu的99.6%。

For me this takes 30 seconds to execute, and while executing the process takes about 99.6% of a cpu.

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

bool is_ready(false);
std::mutex m;
std::condition_variable cv;

void
test()
{
    std::this_thread::sleep_for(std::chrono::seconds(30));
    std::unique_lock<std::mutex> lk(m);
    is_ready = true;
    cv.notify_one();
}

int
main()
{
    std::thread t(test);
    std::unique_lock<std::mutex> lk(m);
    while (!is_ready)
    {
        cv.wait(lk);
        if (!is_ready)
            std::cout << "Spurious wake up!\n";
    }
    t.join();
}

除了在30秒执行期间,该过程具有完全相同的行为占用了0.0%的CPU。如果您要编写一个可以在电池供电的设备上执行的应用程序,那么后者在电池上的使用几乎是无限的。

This has the exact same behavior except that during the 30 second execution, the process is taking 0.0% cpu. If you're writing an app that might execute on a battery powered device, the latter is nearly infinitely easier on the battery.

现在可以肯定的是,如果您的设备很差, std :: condition_variable 的实现,其效率可能与轮询循环相同。但是实际上,这样的供应商应该很快倒闭。

Now admittedly, if you had a very poor implementation of std::condition_variable, it could have the same inefficiency as the polling loop. However in practice such a vendor ought to go out of business fairly quickly.

更新

对于咧嘴笑,我用一个伪造的唤醒检测器增强了condition_variable等待循环。我再次运行它,它没有打印出任何内容。没有一个虚假的唤醒。当然不能保证。但这确实证明了质量实现可以实现的目标。

For grins I augmented my condition_variable wait loop with a spurious wakeup detector. I ran it again, and it did not print out anything. Not one spurious wakeup. That is of course not guaranteed. But it does demonstrate what a quality implementation can achieve.

这篇关于为什么我需要std :: condition_variable?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆