c++ - boost::asio::deadline_timer 1ms 在一段时间后滞后

标签 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 次。

当我仍然使用间隔为 1 毫秒的计时器时,我无法找出将超时增加到 ~10-15 毫秒的原因。

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

最佳答案

与其等待“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 的内容

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

Note how care is taken to calculate the next event back from the starting point each time, so that INTERVAL may be specified with accuracy that isn't representable in the clock's time_point:

   auto constexpr INTERVAL = 1.0/3ms;

representation. Doing otherwise risks accumulating rounding errors.

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

关于c++ - boost::asio::deadline_timer 1ms 在一段时间后滞后,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49769347/

相关文章:

c++ - OpenGL 绘制有很多缺失的面孔

c++ - boost 线程池

c++ - boost split 不能拆分中文句子

c++ - boost::mpl:如何为超过 50 个条目的列表生成预生成的头文件?

c++ - Qt-GUI有几个 "pages",如何同步几个QWidgets的大小

c++ - 对非 const 对象的 const 引用

c++ - 为什么这会通过 Sigill 信号过早存在?

c++ - 按值或引用传递容器

C++ getline() 与 boost::iostreams::filtering_istream 工作起来很奇怪

c++ - 如何只拆分一次正则表达式?