为什么条件变量会修复我们的功耗?

Bil*_*Yan 13 c++ energy condition-variable thread-sleep

我们正在使用Mac上的音频播放器项目,并注意到电源使用率非常高(约为google chrome执行相同工作负载的7倍).

我使用了xcode的能量分析工具,其中一个问题是我们有太多的CPU唤醒开销.

根据xcode:

每次CPU从空闲状态唤醒时,都会产生能量损失.如果唤醒很高,并且每次唤醒的CPU利用率很低,那么您应该考虑批处理工作.

我们已经将问题缩小到了一个usleep函数调用.

在我们的代码中,音频解码器是一个生产音频数据并将其插入消费者的生产者 - 音频播放器.我们的音频播放器基于OpenAL,它具有音频数据缓冲区.

因为音频播放器可能比生产者慢,所以我们总是在向音频播放器提供新的音频数据之前检查缓冲器的可用性.如果没有可用的缓冲区,我们会暂停一段时间再试一次.所以代码看起来像:

void playAudioBuffer(Data *data)
{
    while(no buffer is available)
    {
         usleep()
    }
    process data.
}
Run Code Online (Sandbox Code Playgroud)

知道usleep是一个问题,我们做的第一件事就是删除usleep().(因为OpenAL似乎不提供回调或任何其他方式,轮询似乎是唯一的选择.)我们成功地将功耗降低了一半.

然后,昨天,我们尝试了

for(int i =0; i<attempts; ++i)
{
    std::unique_lock<std::mutex> lk(m);
    cv.wait_for(lk, 3, []{
                            available = checkBufferAvailable(); 
                            return available;
                         })

    if (available)
    {
         process buf;
    }
 }
Run Code Online (Sandbox Code Playgroud)

这是我们偶然尝试的一项实验.它对我们来说没有任何意义,因为逻辑上它执行相同的等待.并且条件变量的使用不正确,因为变量"available"只能由一个线程访问.但它实际上减少了90%的能耗,线程的CPU使用量下降了很多.现在我们比铬更好.但条件变量如何实现与以下代码不同?为什么它会节省我们的力量?

mutex lock;
while(condition is false)
{
    mutex unlock;
    usleep();
    mutex lock;
}
...
mutex unlock
...
Run Code Online (Sandbox Code Playgroud)

(我们使用mac的活动监视器(能量编号)和cpu使用情况分析工具来测量能耗.)

小智 1

我可能是错的,但据我了解当你使用条件变量来实现等待缓冲区数据收入时。它所做的主要事情是,它将呈现此条件变量的线程置于睡眠状态,直到与其关联的信号唤醒该线程。这就是为什么您可以减少唤醒开销并更有效地使用资源。

以下是在 Linux 中使用线程的链接,我在那里读到了相关内容:

也许这会让您了解它发生的原因和方式。

再说一次,我并不完全确定我是完全正确的,但在我看来,这是一个正确的方向。

对不起我纯正的英语。