boost :: asio :: deadline_timer一段时间后1ms滞后

时间:2018-04-11 07:47:07

标签: c++ boost

我使用boost :: asio :: deadline_timer实现了一个计时器。 我使用expires_from_now运行一个计时器(boost :: posix_time :: milliseconds(1))

我算一下,它在10秒内(在Windows下)触发的频率。我期待10 000次。

结果如下: 在一台PC计数器上非常准确 - 每10秒10 000次。 在其他PC计数器上随机变化7000到8500。 问题:一段时间后,计数减少到每10秒600-800次。

当我仍然使用1ms间隔的定时器时,我无法找出将超时增加到~10-15ms的原因是什么。

我检查了电源管理中的处理器电源设置 - 最低性能为100%。 Windows中是否存在可能影响不同PC上的结果的其他设置? 为什么在运行程序一段时间后会发生这种情况?

1 个答案:

答案 0 :(得分:0)

而不是等待" x"毫秒,如果您依靠最佳精确度来满足最后期限,请完全说明:

<强> Live On Coliru

#include <boost/asio.hpp>
#include <boost/asio/high_resolution_timer.hpp>
#include <iostream>

namespace ba = boost::asio;
using namespace std::chrono_literals;

int main() {
    ba::io_context io;

    using C = ba::high_resolution_timer::clock_type;
    ba::high_resolution_timer t(io);

    auto next_wakeup = [&t, interval = 10ms] {
        t.expires_at(C::now() + interval);
        t.wait();
    };

    auto until = C::now() + 5s;
    int count = 0;

    do count += 1;
    while (next_wakeup(), C::now() <= until);

    std::cout << "Timer triggered " << count << " times in 5s\n";
}

在我的系统上,它报告497,因此您可以看到循环开销足以错过总共几个截止日期。如果你降低频率,这就变得更加重要。

替代方法

你当然可以使这个东西多线程并在线程之间分配你的计时器事件,这样就会有更少的错过。或者您可以查看experimental scheduler in Boost Thread

之类的内容

如果您更改设计权衡以最大限度地减少错过的事件,则代价(可能)有更频繁的频率/间隔:

  

请注意每次从起点开始计算下一个事件的注意事项,以便INTERVAL可以精确指定time_point在时钟{{1}中无法表示}}:

   auto constexpr INTERVAL = 1.0/3ms;
     

表示。否则可能会累积舍入误差。

<强> Live On Coliru

#include <boost/asio.hpp>
#include <boost/asio/high_resolution_timer.hpp>
#include <boost/thread.hpp>
using namespace std::chrono_literals;

namespace /*static*/ {
    auto constexpr INTERVAL = 1ms;
    auto constexpr DURATION = 5s;
    std::atomic_int count {0};

    void on_timer_event() { ++count; }
}

namespace ba = boost::asio;
using Timer = ba::high_resolution_timer;
using C = Timer::clock_type;

template <typename Interval>
static void timer_chain(Timer& t, C::time_point start_point, Interval ival, int n = 0) {
    t.expires_at(start_point + std::chrono::duration_cast<C::duration>(n * ival));

    t.async_wait([=,&t](auto ec) {
            if (!ec) {
                on_timer_event();
                timer_chain(t, start_point, ival, n+1);
            }
        });
}

#include <iostream>
int main() {
    ba::io_context io;
    boost::thread_group tg;

    std::list<Timer> timers;

    auto const slices = 10;
    auto const start_point = C::now();
    auto group_interval = INTERVAL * slices;

    for (auto slice = 0; slice<slices; ++slice)
        timer_chain(timers.emplace_back(io), start_point + slice*INTERVAL, group_interval);

    for (unsigned i = 0; i < std::thread::hardware_concurrency(); ++i)
        tg.create_thread([&io] { io.run_for(DURATION); });

    std::cout << "Running on " << tg.size() << " threads...\n";

    tg.join_all();

    std::cout << "Event triggered " << count << " times in " << (C::now() - start_point)/1ms << "ms\n";
}

打印

Running on 1 threads...
Event triggered 5002 times in 5001ms

或者,在我的系统上:

Running on 8 threads...
Event triggered 5002 times in 5001ms