C++ 我可以传递给std::thread::sleep_for()和sleep_until()的最大值是多少?

C++ 我可以传递给std::thread::sleep_for()和sleep_until()的最大值是多少?,c++,sleep,chrono,C++,Sleep,Chrono,《永远沉睡》有一个答案提到: std::this_thread::sleep_until( std::chrono::time_point<std::chrono::system_clock>::max()); 在Visual C++ 2017中运行这个代码实际上根本就不睡觉。我没有签出sleep\u until()案例,所以我不确定那里发生了什么 在sleep\u for()情况下,通过将给定的持续时间添加到system\u clock::now(),然后将其转发到sle

《永远沉睡》有一个答案提到:

std::this_thread::sleep_until(
    std::chrono::time_point<std::chrono::system_clock>::max());

在Visual C++ 2017中运行这个代码实际上根本就不睡觉。我没有签出

sleep\u until()
案例,所以我不确定那里发生了什么

sleep\u for()
情况下,通过将给定的
持续时间添加到
system\u clock::now()
,然后将其转发到
sleep\u until()
,可以将其转换为绝对时间。问题是加法溢出,给了一个过去的时间

查看30.3.2中的C++17草案,无论是
sleep\u till()
还是
sleep\u for()
似乎都没有提到限制。计时规范(30.2.4)中没有任何相关内容。至于
duration::max()
,在
duration\u values
(20.17.4.3)中描述为:“返回的值应大于
zero()
”,这一点都没有帮助

老实说,我很惊讶地看到
sleep\u for()
system\u clock::duration::max()
中失败,因为这是一个对我来说非常有意义的构造


我能传递给那些行为定义良好的函数的最高值是什么?

从技术上讲
std::chrono::system\u clock::durat‌​ion::max()
应该睡很长时间(比你或你的孙子孙女活得更长)。标准强制执行这一点

但实际上,实现人员仍在学习如何处理由不同精度的持续时间之间的
chrono
转换引起的溢出。所以bug很常见

9'000h
(一年多一点)可能更实用。这不可能导致溢出。对于你的申请来说,这肯定是“永远”的

但是,不要犹豫,向您的供应商发送错误报告,抱怨
std::chrono::system\u clock::durat‌​ion::max()
不起作用。应该这样。要让它正常工作是很棘手的。而且让它工作是不可移植的,所以要求您编写一些包装来完成它是不合理的


受以下优秀评论的激励,该评论要求提供参考:

30.3.3[thread.thread.this]/p7,它描述了
的睡眠,说明:

效果:在
rel\u time
指定的相对超时(30.2.4)内阻止调用线程

30.2.4[thread.req.timing]是螺纹支撑库中所有计时要求的规范,说明:

2实现在从超时返回时必然会有一些延迟。中断响应、函数返回和调度中的任何开销都会导致“实现质量”延迟,表示为持续时间
D
i。理想情况下,该延迟为零。此外,对处理器和内存资源的任何争用都会导致“管理质量”延迟,表示为持续时间
D
m。延迟持续时间可能因超时而异,但在所有情况下,越短越好

3名称以结尾的成员函数采用指定持续时间的参数。这些函数产生相对超时。实现应使用稳定的时钟来测量这些函数的时间。330给定持续时间参数
D
t,超时的实时持续时间为
D
t
+D
i
+D
m

好吧,现在我觉得很有趣,因为我们不是在讨论成员函数。我们讨论的是一个名称空间作用域函数。这是一个缺陷。请随意

但是规范没有提供溢出的宽限。规范(几乎)明确指出,在指定的延迟之后,实现才能返回。它是含糊不清的多少后,但明确的是,它不能返回之前

如果你“窃听”STL,而他不合作,就把他介绍给我,我们会解决的。:-)也许有一个我没有看到的标准错误,应该被修复。如果是这样的话,我可以帮助您根据标准而不是VS来提交错误。或者VS已经解决了这个问题,并且可以在升级中进行修复

如果这是VS中的一个bug,请让STL知道我非常乐意帮助修复它。在不同的平台上解决这个问题有不同的权衡

目前,我不能保证在我自己的实现(libc++)中没有此类错误。所以这里没有高人一等的事。对于std::lib来说,这是一个很难正确处理的领域

更新

我已经查看了libc++
sleep\u的
sleep\u,直到
sleep\u for
通过“长时间”睡眠(尽可能多的睡眠时间)正确处理溢出<代码>睡眠直到出现溢出错误

下面是一个经过简单测试的固定睡眠模式:

template <class _Clock, class _Duration>
void
sleep_until(const chrono::time_point<_Clock, _Duration>& __t)
{
    using namespace chrono;
    using __ldsec = duration<long double>;
    _LIBCPP_CONSTEXPR time_point<_Clock, __ldsec> _Max =
                          time_point<_Clock, nanoseconds>::max();
    time_point<_Clock, nanoseconds> __ns;
    if (__t < _Max)
    {
        __ns = time_point_cast<nanoseconds>(__t);
        if (__ns < __t)
            __ns += nanoseconds{1};
    }
    else
        __ns = time_point<_Clock, nanoseconds>::max();
    mutex __mut;
    condition_variable __cv;
    unique_lock<mutex> __lk(__mut);
    while (_Clock::now() < __ns)
        __cv.wait_until(__lk, __ns);
}
人们可以把
lcm\u类型
看作是
common\u类型
的反面。前者找到的持续时间,转换为只会分割。后者找到一个转换为仅倍数的持续时间。

未指定,它将溢出 我曾与比利奥尼尔,一个Visual C++标准库开发人员,以及LIbc++的主要作者Howard Hinnant讨论过。我的结论是线程库中的
\u和
\u until
族将以未指定的方式溢出,您不应该尝试向它们传递较大的值。我不清楚该标准是否在该主题上规定不足

问题 所有定时功能1都采用
持续时间
时间点
。两者都由其基础类型(表示)和比率(期间)定义。周期也可以被视为一个“单位”,例如一秒或纳秒

可能发生溢流的地方主要有两个:

  • 在平台特定呼叫之前,以及
  • 杜尔
    template <class _Clock, class _Duration>
    void
    sleep_until(const chrono::time_point<_Clock, _Duration>& __t)
    {
        using namespace chrono;
        using __ldsec = duration<long double>;
        _LIBCPP_CONSTEXPR time_point<_Clock, __ldsec> _Max =
                              time_point<_Clock, nanoseconds>::max();
        time_point<_Clock, nanoseconds> __ns;
        if (__t < _Max)
        {
            __ns = time_point_cast<nanoseconds>(__t);
            if (__ns < __t)
                __ns += nanoseconds{1};
        }
        else
            __ns = time_point<_Clock, nanoseconds>::max();
        mutex __mut;
        condition_variable __cv;
        unique_lock<mutex> __lk(__mut);
        while (_Clock::now() < __ns)
            __cv.wait_until(__lk, __ns);
    }
    
    namespace detail
    {
    
    template <class Duration0, class ...Durations>
    struct lcm_type;
    
    template <class Duration>
    struct lcm_type<Duration>
    {
        using type = Duration;
    };
    
    template <class Duration1, class Duration2>
    struct lcm_type<Duration1, Duration2>
    {
        template <class D>
        using invert = std::chrono::duration
                       <
                           typename D::rep,
                           std::ratio_divide<std::ratio<1>, typename D::period>
                       >;
    
        using type = invert<typename std::common_type<invert<Duration1>,
                                                      invert<Duration2>>::type>;
    };
    
    template <class Duration0, class Duration1, class Duration2, class ...Durations>
    struct lcm_type<Duration0, Duration1, Duration2, Durations...>
    {
        using type = typename lcm_type<
                         typename lcm_type<Duration0, Duration1>::type,
                         Duration2, Durations...>::type;
    };
    
    }  // namespace detail
    
    auto s = duration_cast<seconds>(time);
    auto ns = duration_cast<nanoseconds>(time - s);
    
    timespec ts = { s.count(), ns.count() };
    nanosleep(&ts, &ts);
    
    std::this_thread::sleep_for(hours::max());
    
    this_thread::sleep_for(system_clock::durat‌ion::max());