我正在尝试实现一个 C++ 代码,该代码应该以不同的时间间隔调用三个彼此独立的不同方法。 例如,假设 method_1 应该每 T1 秒调用一次,method_2 应该每 T2 秒调用一次,最后 method3 应该以 T3 秒的间隔执行。
我可以像下面这样实现吗?在单个线程内顺序调用这些方法是否会使它们相互依赖?假设method1的间隔为100s,T2为1s。 调用method1不是会阻塞每1s调用method2吗?
is io_context.run() 方法是否使它们的调用彼此独立?
enum MethodTypes { FIRST = 0, SECOND = 1, THIRD = 2 };
struct TestTimerContext {
boost::asio::steady_timer timer;
NssStatsTimerContext(boost::asio::io_context& io) : timer(io) {}
};
假设以下所有方法都在类中定义。
start_process (vector<bool> condistions, vector<uint32> intervals) {
if (conditions[0]) {
boost::asio::io_context io_context_first;
start_method (intervals[0], MethodTypes::FIRST, io_context_1);
}
if (conditions[1]) {
boost::asio::io_context io_context_2;
start_method (intervals[0], MethodTypes::FIRST, io_context_2);
}
if (conditions[2]) {
boost::asio::io_context io_context_3;
start_method (intervals[0], MethodTypes::FIRST, io_context_3);
}
}
start_method (uint32 interval, MethodTypes method_type, boost::asio::io_context io_context) {
io_context.run();
std::unique_ptr<TestTimerContext> ctx;
ctx = std::make_unique<TestTimerContext>(io_context);
auto& ctx_ref = *ctx;
if (interval ==0) {
func_cb( err, interval, method_type);
} else {
ctx_ref.timer.expires_after(std::chrono::milliseconds(interval));
ctx_ref.timer.async_wait([&](const boost::system::error_code& err) mutable {
func_cb( err, interval, method_type);
});
}
}
func_cb (
const boost::system::error_code& err,
uint32_t interval,
MethodTypes method_type) {
if (err) {
cout<<"cb function has an error"<<endl;
return;
}
switch (method_type) {
case MethodTypes::FIRST:
method1();
break;
case MethodTypes::SECOND:
methdo2();
break;
case MethodTypes::THIRD:
method3();
break;
default:
cout<<"method type is not supported"<<end;
return;
}
if (interval == 0) {
// do nothing
} else {
auto ctx = Arc<TestTimerContext>(io_context_);
auto& ctx_ref = *ctx;
ctx_ref.timer.expires_after(std::chrono::milliseconds(interval));
ctx_ref.timer.async_wait([&](const boost::system::error_code& err) mutable {
func_cb(err, interval, method_type);
});
}
}
是的。
您通常会使用单个
io_context
(仅在需要不同的调度时使用分离,例如优先考虑 IO 而非工作)。
由于您的问题代码不是独立的,所以让我选择为您编写一些更简单的代码:
例如,假设 method_1 应该每 T1 秒调用一次,method_2 应该每 T2 秒调用一次,最后 method3 应该以 T3 秒的间隔执行。
static inline void trace(std::string const& msg) {
static auto const start = now();
std::cout << std::setw(10) << (now() - start) / 1ms << "ms " << quoted(msg) << std::endl;
}
int main() {
trace("main");
asio::io_context ioc;
IntervalTimer t1(ioc.get_executor(), 1s, [] { trace("Method 1"); });
IntervalTimer t2(ioc.get_executor(), 1500ms, [] { trace("Method 2"); });
IntervalTimer t3(ioc.get_executor(), 1200ms, [] { trace("Method 3"); });
ioc.run_for(6s);
trace("exit");
}
为此,我发明了
IntervalTimer
来封装计时器对象和异步回调循环:
template <typename Callback> struct IntervalTimer {
IntervalTimer(asio::any_io_executor ex, duration interval, Callback callback)
: interval_(interval)
, cb_(std::move(callback))
, tim_(ex, interval_)
{
loop();
}
private:
void loop() {
while (tim_.expiry() <= now())
tim_.expires_at(tim_.expiry() + interval_);
tim_.async_wait([this](error_code ec) {
if (!ec) { // aborted or other failure
cb_();
loop();
}
});
}
duration interval_;
Callback cb_;
asio::steady_timer tim_;
};
看到它在Coliru上直播
#include <boost/asio.hpp>
#include <iomanip>
#include <iostream>
namespace asio = boost::asio;
using namespace std::chrono_literals;
using duration = std::chrono::steady_clock::duration;
static constexpr auto now = std::chrono::steady_clock::now;
using boost::system::error_code;
template <typename Callback> struct IntervalTimer {
IntervalTimer(asio::any_io_executor ex, duration interval, Callback callback)
: interval_(interval)
, cb_(std::move(callback))
, tim_(ex, interval_)
{
loop();
}
private:
void loop() {
while (tim_.expiry() <= now())
tim_.expires_at(tim_.expiry() + interval_);
tim_.async_wait([this](error_code ec) {
if (!ec) { // aborted or other failure
cb_();
loop();
}
});
}
duration interval_;
Callback cb_;
asio::steady_timer tim_;
};
static inline void trace(std::string const& msg) {
static auto const start = now();
std::cout << std::setw(10) << (now() - start) / 1ms << "ms " << quoted(msg) << std::endl;
}
int main() {
trace("main");
asio::io_context ioc;
IntervalTimer t1(ioc.get_executor(), 1s, [] { trace("Method 1"); });
IntervalTimer t2(ioc.get_executor(), 1500ms, [] { trace("Method 2"); });
IntervalTimer t3(ioc.get_executor(), 1200ms, [] { trace("Method 3"); });
ioc.run_for(6s);
trace("exit");
}
用我本地的互动演示: