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::duration::max()
应该睡很长时间(比你或你的孙子孙女活得更长)。标准强制执行这一点
但实际上,实现人员仍在学习如何处理由不同精度的持续时间之间的chrono
转换引起的溢出。所以bug很常见
睡9'000h
(一年多一点)可能更实用。这不可能导致溢出。对于你的申请来说,这肯定是“永远”的
但是,不要犹豫,向您的供应商发送错误报告,抱怨std::chrono::system\u clock::duration::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::duration::max());