我可以使用 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");
}

输出

g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
         0ms "main"
      1000ms "Method 1"
      1200ms "Method 3"
      1500ms "Method 2"
      2000ms "Method 1"
      2400ms "Method 3"
      3000ms "Method 1"
      3000ms "Method 2"
      3600ms "Method 3"
      4000ms "Method 1"
      4500ms "Method 2"
      4800ms "Method 3"
      5000ms "Method 1"
      6000ms "Method 1"
      6000ms "exit"

用我本地的互动演示:

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