不要等待“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 中表示:
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