我可以独立使用 boost::asio::io_context 来独立使用不同时间间隔的不同方法吗?

问题描述 投票:0回答:1

我正在尝试实现一个 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);
        });
    }
}
c++ boost boost-asio
1个回答
0
投票

是的。

您通常会使用单个

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");
}

用我本地的互动演示:

© www.soinside.com 2019 - 2024. All rights reserved.