C++11 std::this_thread::sleep_for()和纳秒

C++11 std::this_thread::sleep_for()和纳秒,c++11,g++,thread-sleep,C++11,G++,Thread Sleep,如果我将两个调用并排放置,以确定可测量的最小持续时间: // g++ -std=c++11 -O3 -Wall test.cpp #include <chrono> typedef std::chrono::high_resolution_clock hrc; hrc::time_point start = hrc::now(); hrc::time_point end = hrc::now(); std::chrono::nanoseconds duration = end

如果我将两个调用并排放置,以确定可测量的最小持续时间:

// g++ -std=c++11 -O3 -Wall test.cpp
#include <chrono>
typedef std::chrono::high_resolution_clock hrc;

hrc::time_point start = hrc::now();
hrc::time_point end   = hrc::now();
std::chrono::nanoseconds duration = end - start;
std::cout << "duration: " << duration.count() << " ns" << std::endl;
//g++-std=c++11-O3-Wall test.cpp
#包括
typedef std::chrono::高分辨率时钟hrc;
hrc::time_point start=hrc::now();
hrc::time_point end=hrc::now();
std::chrono::纳秒持续时间=结束-开始;
标准::cout
什么能解释这些数字

有一个非常明显的模式,你所有的结果总是比你要求的睡眠时间长54000ns。如果你看看GCC的
this_thread::sleep_for()
是如何在GNU/Linux上实现的,你会发现它只使用了
nanosplep
,正如Cubbi的评论所说,调用该函数大约需要50000ns。我猜其中一部分成本是进行系统调用,因此从用户空间切换到内核,然后再切换回来

为什么负时间睡眠返回200+ns,而0+纳秒睡眠返回50000+纳秒

我猜C库会检查负数,不会进行系统调用

作为睡眠时间的负数是一个记录在案的/受支持的特性,还是我偶然发现了一些我无法依赖的奇怪错误

该标准不禁止传递负参数,因此它是允许的,并且函数应该返回“立即”,因为相对超时指定的时间已经过了。但是,不能依赖于负参数比非负参数返回得更快,这是特定实现的产物

有更好的C++睡眠调用,它能给我更多的一致/可预测的睡眠时间吗?

我不这么认为-如果我知道一个,那么我们将在GCC中使用它来实现
这个线程::sleep\u for()

编辑:在GCC最新版本的libstdc++中,我添加了:

if (__rtime <= __rtime.zero())
  return;

if(uu rtime在内核init中/init_task.c在struct task中

.timer_slack_ns = 50000, /* 50 usec default slack */
它在hrtimer\u nanosleep()内核函数中添加了非RT进程,以减少计时器的硬件使用频率。

受其答案的启发,我评估了
计时器松弛
调度FIFO
的效果。对于
计时器松弛
,您必须添加

#include <sys/prctl.h> // prctl
⋮
prctl (PR_SET_TIMERSLACK, 10000U, 0, 0, 0);
我使用GUI(Debian 9.11,内核)在桌面系统上运行了的代码片段 4.9.189-3+deb9u2,g++9.2-O3,英特尔®核心™ i5-3470T CPU@2.90GHz)。第一种情况(后续时间测量)的结果如下

由于其间没有系统调用,延迟约为260ns,且不受过程设置的显著影响。对于正态分布计时,图表为直线,横坐标值为0.5,为平均值,斜率表示标准偏差。测量值与存在更高延迟的异常值

与此相反,第二种情况(睡眠1纳秒)在进程设置之间有所不同,因为它包含系统调用。因为睡眠时间很短,睡眠不会增加任何时间。因此,图表仅显示开销

如所述,开销默认为约64µs(此处稍大一些)。通过将
计时器松弛时间
降低到10µs,并调用priviledged
调度程序()可将时间减少到约22µs
开销可以降低到约12µs。但如图所示,即使在这种情况下,延迟也可以超过50µs(在0.0001%的运行中)


这些测量结果显示了进程设置开销的基本依赖关系。其他测量结果表明,在非GUI XEON服务器系统上,波动要小一个数量级以上。

这就是
nanosleep({0,1},NULL)
所需的时间(如果您有linux)我无法复制这些结果,睡眠\u(1ns)给我0n.<代码>睡眠>睡眠>至少在指定的持续时间内。如果你提供一个负值,它根本不需要睡觉。<代码>睡眠< /C>是一个利基工具。你应该使用某种计时器机制(SAD标准C++没有任何)。请注意,你的
sleep_for
是在测量
sleep_for
调用的开销:你不能期望它花费零时间,因为它必须检查它是否应该花费零时间,这需要的时间超过零时间!但是,请记住,如果你睡的时间是负的,那么它符合睡眠7年零7个月的要求。它是始终遵守比请求的睡眠时间更长的睡眠时间。如果需要少得可笑的睡眠时间,则需要忙循环,因为节省cpu的睡眠时间最终会在其他代码运行时等待中断……在Linux内核中,一个用户空间进程调用nanosleep()除非进程被标记为实时优先级,否则将在下一个调度程序唤醒间隔(通常为“jiffy”)触发。请参阅libstdc++使用nanosleep实现此线程::sleep,如果tv_sec为负值,nanosleep将返回EINVAL(可能立即返回)。
#include <sys/prctl.h> // prctl
⋮
prctl (PR_SET_TIMERSLACK, 10000U, 0, 0, 0);
#include <unistd.h>    // getpid
#include <sched.h>     // sched_setscheduler
⋮
    const pid_t pid {getpid ()};
    struct sched_param sp = {.sched_priority = 90};
    if (sched_setscheduler (pid, SCHED_FIFO, &sp) == -1) {
        perror ("sched_setscheduler");
        return 1;
    }