Boost.Thread在1.58中醒来太晚 [英] Boost.Thread wakes up too late in 1.58

查看:60
本文介绍了Boost.Thread在1.58中醒来太晚的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个需要在特定窗口内工作的应用程序(在这种情况下,所有窗口都相隔30秒).当时间不在窗口内时,将计算到下一个窗口中间的时间,并且线程在该时间段内睡眠(以毫秒为单位,使用boost::this_thread::sleep_for).

I have an application that needs to do work within certain windows (in this case, the windows are all 30 seconds apart). When the time is not within a window, the time until the middle of the next window is calculated, and the thread sleeps for that amount of time (in milliseconds, using boost::this_thread::sleep_for).

使用Boost 1.55,我能够以极高的可靠性击中公差范围内(+/- 100ms)的窗户.迁移到Boost 1.58时,我再也无法访问这些窗口.将boost::this_thread::sleep_for替换为std::this_thread::sleep_for可以解决此问题;但是,我需要boost::thread的可中断功能和boost::this_thread::sleep_for提供的中断点.

Using Boost 1.55, I was able to hit the windows within my tolerance (+/-100ms) with extreme reliability. Upon migration to Boost 1.58, I am never able to hit these windows. Replacing the boost::this_thread::sleep_for with std::this_thread::sleep_for fixes the issue; however, I need the interruptible feature of boost::thread and the interruption point that boost::this_thread::sleep_for provides.

以下是说明此问题的一些示例代码:

Here is some sample code illustrating the issue:

#include <boost/thread.hpp>
#include <boost/chrono.hpp>

#include <chrono>
#include <iostream>
#include <thread>

void boostThreadFunction ()
{
   std::cout << "Starting Boost thread" << std::endl;
   for (int i = 0; i < 10; ++i)
   {
      auto sleep_time = boost::chrono::milliseconds {29000 + 100 * i};
      auto mark = std::chrono::steady_clock::now ();
      boost::this_thread::sleep_for (sleep_time);
      auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
         std::chrono::steady_clock::now () - mark);
      std::cout << "Boost thread:" << std::endl;
      std::cout << "\tSupposed to sleep for:\t" << sleep_time.count () 
                << " ms" << std::endl;
      std::cout << "\tActually slept for:\t" << duration.count () 
                << " ms" << std::endl << std::endl;
   }
}

void stdThreadFunction ()
{
   std::cout << "Starting Std thread" << std::endl;
   for (int i = 0; i < 10; ++i)
   {
      auto sleep_time = std::chrono::milliseconds {29000 + 100 * i};
      auto mark = std::chrono::steady_clock::now ();
      std::this_thread::sleep_for (sleep_time);
      auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
         std::chrono::steady_clock::now () - mark);
      std::cout << "Std thread:" << std::endl;
      std::cout << "\tSupposed to sleep for:\t" << sleep_time.count () 
                << " ms" << std::endl;
      std::cout << "\tActually slept for:\t" << duration.count () 
                << " ms" << std::endl << std::endl;
   }
}

int main ()
{
   boost::thread boost_thread (&boostThreadFunction);
   std::this_thread::sleep_for (std::chrono::seconds (10));
   std::thread std_thread (&stdThreadFunction);
   boost_thread.join ();
   std_thread.join ();
   return 0;
}

以下是将Boost 1.58引用为包含目录并在我的工作站(Windows 7 64位)上运行时的输出:

Here is the output when referencing Boost 1.58 as an include directory and running on my workstation (Windows 7 64-bit):

Starting Boost thread
Starting Std thread
Boost thread:
        Supposed to sleep for:  29000 ms
        Actually slept for:     29690 ms

Std thread:
        Supposed to sleep for:  29000 ms
        Actually slept for:     29009 ms

Boost thread:
        Supposed to sleep for:  29100 ms
        Actually slept for:     29999 ms

Std thread:
        Supposed to sleep for:  29100 ms
        Actually slept for:     29111 ms

Boost thread:
        Supposed to sleep for:  29200 ms
        Actually slept for:     29990 ms

Std thread:
        Supposed to sleep for:  29200 ms
        Actually slept for:     29172 ms

Boost thread:
        Supposed to sleep for:  29300 ms
        Actually slept for:     30005 ms

Std thread:
        Supposed to sleep for:  29300 ms
        Actually slept for:     29339 ms

Boost thread:
        Supposed to sleep for:  29400 ms
        Actually slept for:     30003 ms

Std thread:
        Supposed to sleep for:  29400 ms
        Actually slept for:     29405 ms

Boost thread:
        Supposed to sleep for:  29500 ms
        Actually slept for:     29999 ms

Std thread:
        Supposed to sleep for:  29500 ms
        Actually slept for:     29472 ms

Boost thread:
        Supposed to sleep for:  29600 ms
        Actually slept for:     29999 ms

Std thread:
        Supposed to sleep for:  29600 ms
        Actually slept for:     29645 ms

Boost thread:
        Supposed to sleep for:  29700 ms
        Actually slept for:     29998 ms

Std thread:
        Supposed to sleep for:  29700 ms
        Actually slept for:     29706 ms

Boost thread:
        Supposed to sleep for:  29800 ms
        Actually slept for:     29998 ms

Std thread:
        Supposed to sleep for:  29800 ms
        Actually slept for:     29807 ms

Boost thread:
        Supposed to sleep for:  29900 ms
        Actually slept for:     30014 ms

Std thread:
        Supposed to sleep for:  29900 ms
        Actually slept for:     29915 ms

我希望std::threadboost::thread睡眠相同的时间;但是,当boost::thread被要求睡眠29.1-29.9秒时,它似乎想睡眠30秒.我是在滥用boost::thread界面,还是从1.55开始引入的错误?

I would expect the std::thread and the boost::thread to sleep for the same amount of time; however, the boost::thread seems to want to sleep for ~30 seconds when asked to sleep for 29.1 - 29.9 seconds. Am I misusing the boost::thread interface, or is this a bug that was introduced since 1.55?

推荐答案

我是对Boost.Thread进行上述更改的人. 1.58中的更改是经过与Boost社区和Microsoft进行了一段时间的协商后设计得出的,并且可能导致移动设备的电池寿命大大提高. C ++标准不保证任何计时等待实际上会等待,或者等待正确的时间,或者接近正确时间的任何时间.因此,任何假定计时等待工作或准确的代码都是错误的.将来的Microsoft STL可能会对Boost.Thread进行类似的更改,因此STL行为将与Boost.Thread相同.我可能会补充说,在任何非实时操作系统上,任何定时等待本质上都是无法预测的,任何触发都可能比请求晚得多.因此,社区认为此更改有助于揭露STL的错误使用.

I am the person who committed the above change to Boost.Thread. This change in 1.58 is by design after a period of consultation with the Boost community and Microsoft, and results in potentially enormous battery life improvements on mobile devices. The C++ standard makes no guarantees whatsoever that any timed wait actually waits, or waits the correct period, or anything close to the correct period. Any code written to assume that timed waits work or are accurate is therefore buggy. A future Microsoft STL may make a similar change to Boost.Thread, and therefore the STL behaviour would be the same as Boost.Thread. I might add that on any non-realtime OS any timed wait is inherently unpredictable any may fire very considerably later than requested. This change was therefore thought by the community as helpful to expose buggy usage of the STL.

此更改使Windows可以选择将计时器延迟一定时间触发.它实际上可能没有这样做,并且实际上只是在最新版本的Windows上尝试延迟常规中断,这是无滴答的内核设计的一部分.即使您指定了几周的时间,由于总是将正确的截止日期发送到Windows,因此在计时器到期后发生的下一个系统中断将始终触发计时器,因此,计时器最多不会延迟几秒钟.

The change allows Windows to optionally fire timers late by a certain amount. It may not actually do so, and in fact simply tries to delay regular interrupts as part of a tickless kernel design on very recent editions of Windows. Even if you specify a tolerance of weeks, as the correct deadline is always sent to Windows the next system interrupt to occur after the timer expiry will always fire the timer, so no timer will ever be late by more than a few seconds at most.

此更改解决的一个错误是系统睡眠问题.先前的实现可能会由于系统睡眠而感到困惑,因为定时等待永远不会唤醒(好在29天之内).此实现可正确处理系统睡眠,而希望由系统睡眠引起的使用Boost.Thread的随机代码挂起已成为过去.

One bug fixed by this change was the problem of system sleep. The previous implementation could get confused by the system sleeping whereby timed waits would never wake (well, in 29 days they would). This implementation correctly deals with system sleeps, and random hangs of code using Boost.Thread caused by system sleeps hopefully is now a thing of the past.

最后,我个人认为定时等待需要STL中的硬度/柔软度保证.但是,这是一个很大的变化.而且即使实施,除非在硬实时OS上进行定时等待,否则只能尽力而为.这就是为什么它们首先被排除在C ++标准之外的原因,因为C ++ 11在将移动设备的功耗视为足以修改API之前就已经完成了定稿.

Finally, I personally think that timed waits need a hardness/softness guarantee in the STL. That's a pretty big change however. And even if implemented, except on hard realtime OSs hardness of timed waits can only ever be best effort. Which is why they were excluded from the C++ standard in the first place, as C++ 11 was finalised well before mobile device power consumption was considered important enough to modify APIs.

Niall

这篇关于Boost.Thread在1.58中醒来太晚的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆