为什么 std::future::wait_for 不等待正确的持续时间

Why does std::future::wait_for not wait for the correct duration?

本文关键字:等待 持续时间 for std future wait 为什么      更新时间:2023-10-16

我不明白为什么当指定的持续时间增加时,调用std::future::wait_for时测量的持续时间和指定持续时间之间的差异会增加。

当我告诉std::future等待 10ns 并测量经过的时间时,我得到 ~2000ns。现在,10ns 是一个非常短的持续时间,因此可能需要等待这么短的时间,相关函数调用涉及太多开销。但是当我告诉std::future等待 100000ns 并测量经过的时间时,我得到 ~150000ns。分别等待 10 微秒和 100 微秒时可以看到类似的效果。

#include <chrono>
#include <future>
#include <iostream>
#include <thread>
using namespace std::chrono;
using namespace std::chrono_literals;
void f() { std::this_thread::sleep_for(1s); }
int main() {
  steady_clock::time_point start, end;
  std::future<void> future = std::async(std::launch::async, f);
  start = steady_clock::now();
  future.wait_for(10ns);
  end = steady_clock::now();
  std::cout << "10 -> " << (end - start).count() << 'n';
  start = steady_clock::now();
  future.wait_for(100000ns);
  end = steady_clock::now();
  std::cout << "100000 -> " << (end - start).count() << 'n';
  return 0;
}

我用 g++ future_test.cpp -lpthread 编译上面的代码,在 Ubuntu 18.04 上使用 g++ 7.3.0。

我可以解释类似的东西

10 -> 2000
100000 -> 102000

但这不是我得到的。以下是多次执行的代表性结果:

10 -> 2193
100000 -> 154723

为什么 100'000ns 的测量持续时间比指定持续时间超过 ~2'000ns?

引用

文档:

std::future_status wait_for( const std::chrono::duration& timeout_duration );

由于以下原因,此功能的阻塞时间可能会超过 timeout_duration 计划或资源争用延迟。

睡觉和等待只承诺至少等你问的时间。由于硬件和计划限制引入了不可预测的延迟,因此睡眠或等待可能持续多长时间没有固定的最大值。

对于周期性应用程序(如计时器(,如果您等到一个时间点,然后将该时间点增加固定量,则可以获得稳定的睡眠(平均(。如果继续这样做,只要线程唤醒的频率足够高,您将在一段时间内平均获得目标延迟。

4 GHz 时钟为每刻 0.25 秒。 10 ns 是 40 个即时报价,或 40 条指令给出或接受。

要求10 ns的

延迟意味着任何事情都是非常荒谬的;计算当前时间所需的时间可能很容易超过10 ns。

所以你在这里测量的是:

start = steady_clock::now();
future.wait_for(10ns);
end = steady_clock::now();
std::cout << "10 -> " << (end - start).count() << 'n';

计算当前时间所需的时间,等待开销(检查它是否准备就绪等(。

在第二种情况下:

start = steady_clock::now();
future.wait_for(100000ns);
end = steady_clock::now();
std::cout << "100000 -> " << (end - start).count() << 'n';

相差约为 50,000 ns。 那是 1/20000 秒。

在这里,我们可能会做一些事情,例如将CPU置于低功耗模式,甚至设置旋转锁。

您可能正在切换上下文,但我猜不是;切换到另一个上下文然后再切换回来可能会花费太多时间在这里打扰。

交互式操作系统上的时间切片通常在 1/50 秒的数量级,或者当 CPU 中存在争用时,大约为 20000000ns。

您要求的是实时内容,这与系统非常相关。这是操作系统的工作。但即使你使用RTOS,或者preempt-RT或类似的东西,我也不确定C++stdlib是否可以获得这种准确性。

当您需要它时,如果系统可以为您提供它,则最好求助于依赖于操作系统的调用。

无论如何,在 1ms 精度的范围内,我通常会旋转。但请注意:您将有异常值。