什么时候适合使用 C++11 *_until 超时函数而不是相应的 *_for 函数?
Posted
技术标签:
【中文标题】什么时候适合使用 C++11 *_until 超时函数而不是相应的 *_for 函数?【英文标题】:When is it appropriate to use a C++11 *_until timeout function instead of the corresponding *_for function? 【发布时间】:2012-06-27 09:11:39 【问题描述】:在 C++11 中,*_until
超时函数仅在使用稳定时钟(即仅以不变速率向前移动的时钟)时才会“按预期”运行。因为system_clock
不是一个稳定的时钟,这意味着像这样的代码会表现得非常令人惊讶:
using namespace std::chrono;
std::this_thread::sleep_until(system_clock::now() + seconds(10));
这将导致当前线程休眠 10 秒,除非在休眠期间调整系统时钟,例如夏令时。如果在睡眠期间将时钟调回一小时,则当前线程将睡眠一小时十秒。
据我所知,C++11 中的每个 *_until
超时函数都有一个对应的 *_for
函数,它需要一个持续时间而不是一个时间点。比如上面的代码可以改写如下:
using namespace std::chrono;
std::this_thread::sleep_for(seconds(10));
*_for
函数不必担心在函数执行时会调整时钟,因为它们只是说明等待多长时间,而不是等待结束时应该是什么时间。
此问题影响的不仅仅是睡眠函数,对于基于超时的 future 等待和 try_lock 函数也是如此。
我能想到的唯一一种情况是,当你想要考虑时钟调整时,例如,你想睡觉直到下周三凌晨 3 点 30 分,即使从现在到那个时候夏令时之间有变化。在其他情况下*_until
函数比*_for
函数更有意义吗?如果不是,是否可以肯定地说,一般来说,*_for
超时函数应该优于 *_until
函数?
【问题讨论】:
那不取决于时钟的稳定性吗?wait_for
和 wait_until
是否真的打算在处理“时钟跳跃”时有所不同?
@K-ballo:对,这就是为什么我特别提到时钟稳定性和 system_clock 不稳定的原因。 _for
和 _until
函数在时钟调整方面表现不同,但我不清楚意图是什么。
system_clock
的稳定性实际上是依赖于实现的。
@K-ballo:是的,你是对的。我应该说 system_clock 不能保证是稳定的。然而,我的理解是 system_clock 应该对应于挂钟时间,这意味着在观察夏令时的语言环境中,它将向前和向后调整,并且有时人们会期望它被调整为补偿本地机器上的时间漂移。在实践中,我认为 system_clock 保持稳定是不常见的。
std::this_thread::sleep_for(seconds(10));使用稳定的时钟而不是 system_clock,因此您在原始问题中声称的实际上是相等的 - 取决于实现。
【参考方案1】:
sleep_until
的一个很好的用途是稳定时间循环(如游戏循环)。如果您不确定处理一个周期需要多长时间,但它通常必须具有某个最小长度,您可以增加要休眠的 time_point 直到周期周期。例如:
// requires C++14
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
using namespace std::chrono;
using namespace std::literals;
int main()
auto start_time = steady_clock::now();
for (auto i = start_time; i <= start_time + 1s; i += 50ms)
this_thread::sleep_until(i);
cout << "processing cycle..." << endl;
return 0;
但是当一个周期花费的时间比增量时间长时,您可能必须跟踪滞后。
这个想法是,如果您天真地 sleep_for
,您将在循环周期中休眠加上运行循环内代码所需的时间。
【讨论】:
【参考方案2】:xxx_until
电话是在您有截止日期时拨打的。典型的用例是您对包含多个等待的一段代码有严格的时间限制,或者等待之前每个步骤所消耗的时间是不可预测的。
例如
void foo()
std::chrono::steady_clock::time_point const timeout=
std::chrono::steady_clock::now()+std::chrono::milliseconds(30);
do_something_which_takes_some_time();
if(some_future.wait_until(timeout)==std::future_status::ready)
do_something_with(some_future.get());
这只会处理来自some_future
的值,前提是它在开始后30 毫秒内准备就绪,包括do_something_which_takes_some_time()
所用的时间。
在本例中,xxx_until
函数的大多数用例都将使用稳定的时钟,以实现可预测的超时。
我可以想象使用具有非稳定时钟(例如 std::chrono::system_clock
)的 xxx_until
函数的唯一情况是超时是用户可见的,并且取决于所选时钟的值。闹钟或提醒程序是一个例子,“午夜”运行的备份程序是另一个例子。
【讨论】:
【参考方案3】:sleep_until
函数的一个用例是,如果您想睡到特定时间,而不是特定持续时间。
例如,如果您有一个只应在每天下午 3 点激活的线程,您要么必须计算与 sleep_for
一起使用的持续时间(包括处理夏令时和闰年),或者您可以使用 @987654323 @。
【讨论】:
闹钟是一个很好的例子,说明应该考虑夏令时。您的工作时间已根据 DST 进行了调整,因此您的闹钟也应如此。以上是关于什么时候适合使用 C++11 *_until 超时函数而不是相应的 *_for 函数?的主要内容,如果未能解决你的问题,请参考以下文章
C# Selenium:使用 wait.Until 时无法捕获异常