基于Asio库的定时器,封装实现好用的定时任务

简介: 基于Asio库的定时器,封装实现好用的定时任务

ASIO库介绍


a cross-platform C++ library for network。


Asio 是一个好用的、常用的跨平台的 C++ 库,常用于网络编程、底层的 I/O 编程等 (low-level I/O)。结构框架如下:



详细介绍:xBoost.Asio - 1.78.0


分为boost版和非boost版(不依赖boost库)。


windows下的下载安装推荐使用vcpkg这个工具,vcpkg是命令行包管理工具。


vcpkg工具介绍


在使用第三方库的c或c++开发中可以简化相关的配置操作。vcpkg安装的包支持vs2015和vs2017工具集,目前在windows平台已有超过900多个包,linux平台超过350个包。在默认情况下,vcpkg会优先使用vs2017进行编译。如果未安装,则使用vs2015编译和安装。使用vcpkg对于c或c++开发,令人烦恼的第三方包管理工作大大的减轻。


# vcpkg工具安装,下载vcpkg项目
git clone https://github.com/Microsoft/vcpkg
# 本地编译(windows最好在powershell下)
./bootstrap-vcpkg.bat
# 搜索想要安装的包
vcpkg search asio
# 安装指定的包,包分号后面的表示架构,可用的值为之前列出的那些
vcpkg install asio:x86-windows
# 列出已经安装的包
vcpkg list
# 已安装的包更新
vcpkg upgrade
# 删除已安装的包
vcpkg remove asio:x86-windows


配合cmake使用时注意配置CMAKE_TOOLCHAIN_FILE是否设置为了vcpkg.cmake文件路径。


基于Asio库的定时器封装


工作中,定时任务和定时执行是很常见的功能需求。asio库提供了timer定时器功能asio::steady_timer,可以实现同步和异步的调用机制,但是不封装一下不太好用。


比如以下使用,同步使用:


第一个参数是asio::io_context,第二个参数设置定时器现在开始3秒后终止。wait()是一个阻塞等待,3秒后定时器终止时返回。接着打印“Hello, world!”。


int main()
{  
    asio::io_context ioc;
    asio::steady_timer timer(ioc, std::chrono::seconds(3));
    timer.wait();
    std::cout << "Hello, world!" << std::endl;
    return 0;
}


异步使用时:


async_wait()  执行异步等待,设置回调函数Print,当异步操作结束后(此处即定时器结束后)该函数会被调用。Asio保证回调句柄仅仅能被run()启动的当前线程所调用。如果run() 函数不执行,用于异步等待完成时的回调函数(此处即Print())将永远不会被调用。


void Print(std::error_code ec) {
    std::cout << "Hello, world!" << std::endl;
}
int main()
{  
    asio::io_context ioc;
    asio::steady_timer timer(ioc, std::chrono::seconds(3));
    timer.async_wait(&Print);   
    ioc.run();
    return 0;
}


下例中每隔1秒打印一次计数,从0到2。


async_wait回调函数的签名为 void (std::error_code),传递额外的参数时需要使用bind。Print函数中,计数小于3时,expires_at()推迟定时器的终止时间。async_wait()启动一个新的异步等待。计数大于3时,run()函数返回。


void Print(std::error_code ec, asio::steady_timer* timer, int *count) 
{
    if (*count < 3)
    {
        std::cout << *count << std::endl;
        ++(*count);       
        timer->expires_at(timer->expires_at() + std::chrono::seconds(1));
        timer->async_wait(std::bind(&Print, std::placeholders::_1, timer, count));
    }
}
int main(int argc, char** argv)
{  
    asio::io_context ioc;
    asio::steady_timer timer(ioc, std::chrono::seconds(3));
    int count = 0;
    timer.async_wait(std::bind(&Print,std::placeholders::_1, &timer, &count));
    ioc.run();
    return 0;
}


封装过程


封装后可以直接在回调函数中执行定时的任务了,方便很多,大大简化了使用过程。且可以设置是定时周期执行或者是定时执行指定次数。


#ifndef ARMCORE_INVOKETIMER_HPP
#define ARMCORE_INVOKETIMER_HPP
#include <functional>
#include <memory>
#include <logging.hpp>
#include <asio.hpp>
namespace awesome_asio
{
class InvokeTimer;
typedef std::shared_ptr<InvokeTimer> InvokeTimerPtr;
typedef std::weak_ptr<InvokeTimer> InvokeTimerWPtr;
class InvokeTimer : std::enable_shared_from_this<InvokeTimer>
{
public:
  virtual ~InvokeTimer() {}
  typedef std::function<void()> Function;
  static InvokeTimerPtr CreateTimer(asio::io_context &io, const asio::steady_timer::duration &duration, bool period,
                                    Function &f)
  {
    InvokeTimerPtr it(new InvokeTimer(io, duration, f, period));
    it->self_ = it;
    return it;
  }
  static InvokeTimerPtr CreateTimer(asio::io_context &io, const asio::steady_timer::duration &duration, bool period,
                                    Function &&f)
  {
    InvokeTimerPtr it(new InvokeTimer(io, duration, std::move(f), period));
    it->self_ = it;
    return it;
  }
  static InvokeTimerPtr CreateTimer(asio::io_context &io, const asio::steady_timer::duration &duration,
                                    std::size_t count, Function &f)
  {
    InvokeTimerPtr it(new InvokeTimer(io, duration, f, count));
    it->self_ = it;
    return it;
  }
  static InvokeTimerPtr CreateTimer(asio::io_context &io, const asio::steady_timer::duration &duration,
                                    std::size_t count, Function &&f)
  {
    InvokeTimerPtr it(new InvokeTimer(io, duration, std::move(f), count));
    it->self_ = it;
    return it;
  }
  void Start()
  {
    start_ = std::chrono::system_clock::now();
    timer_.async_wait(std::bind(&InvokeTimer::OnTrigger, this, std::placeholders::_1));
  }
  void Cancel()
  {
    periodic_ = false;
    timer_.cancel();
  }
  inline std::size_t getTickCount() { return trigger_count_; }
  inline int64_t getElapsedMillionsecond() const
  {
    auto end = std::chrono::system_clock::now();
    return std::chrono::duration_cast<std::chrono::milliseconds>(end - start_).count();
  }
  inline int64_t getElapsedSecond() const
  {
    auto end = std::chrono::system_clock::now();
    return std::chrono::duration_cast<std::chrono::seconds>(end - start_).count();
  }
  inline bool isTriggered() const { return isTriggered_; }
private:
  explicit InvokeTimer(asio::io_context &io, const asio::steady_timer::duration &duration, Function &f, bool period)
      : timer_(io, duration),
        duration_(duration),
        periodic_(period),
        callback_(f),
        count_(0),
        trigger_count_(0),
        isTriggered_(false)
  {
  }
  explicit InvokeTimer(asio::io_context &io, const asio::steady_timer::duration &duration, Function &&f, bool period)
      : timer_(io, duration),
        duration_(duration),
        periodic_(period),
        callback_(std::move(f)),
        count_(0),
        trigger_count_(0),
        isTriggered_(false)
  {
  }
  explicit InvokeTimer(asio::io_context &io, const asio::steady_timer::duration &duration, Function &f,
                       std::size_t count)
      : timer_(io, duration),
        duration_(duration),
        periodic_(true),
        callback_(f),
        count_(count),
        trigger_count_(0),
        isTriggered_(false)
  {
  }
  explicit InvokeTimer(asio::io_context &io, const asio::steady_timer::duration &duration, Function &&f,
                       std::size_t count)
      : timer_(io, duration),
        duration_(duration),
        periodic_(true),
        callback_(std::move(f)),
        count_(count),
        trigger_count_(0),
        isTriggered_(false)
  {
  }
  void OnTrigger(const asio::error_code &e)
  {
    if (e.value() != 0)
    {
      self_.reset();
      return;
    }
    isTriggered_ = true;
    trigger_count_++;
    try {
      if (callback_)
        callback_();
    } catch (const std::error_code& errorCode) {
      LOGGING_ERROR("[FATAL] errorCode: %s", errorCode.message());
    }
    if (periodic_)
    {
      if (count_ == 0 || trigger_count_ < count_)
      {
        timer_.expires_at(timer_.expiry() + duration_);
        Start();
      }
      else if (trigger_count_ < count_)
      {
        timer_.expires_at(timer_.expiry() + duration_);
        Start();
      }
      else
        self_.reset();
    }
    else
    {
      self_.reset();
    }
  }
private:
  asio::steady_timer timer_;
  asio::steady_timer::duration duration_;
  bool periodic_;
  std::shared_ptr<InvokeTimer> self_;
  Function callback_;
  std::size_t count_;
  std::size_t trigger_count_;
  std::chrono::system_clock::time_point start_;
  bool isTriggered_;
};
}  // namespace awesome_asio


使用方法


//......
{  
    asio::io_context ioc;
    //......
    InvokeTimer::CreateTimer(ioc,std::chrono::milliseconds(100), true, [this] {
         cout <<"do someting period duration 100ms.."<< endl;         
  });
}


引用:


Boost.Asio - 1.78.0


Windows10下配置Boost_卖萌的大米的博客-CSDN博客_boost windows


vcpkg使用详解_weixin_34293246的博客-CSDN博客


vcpkg 详细介绍_零点零一的博客-CSDN博客_vcpkg是什么


基于Asio 的定时器( asio::steady_timer )_万里归来少年心的博客-CSDN博客_asio 定时器


vcpkg国内镜像使用方法——解决国内下载慢的问题_灵魂制造者的博客-CSDN博客_vcpkg 源

相关文章
|
6月前
|
缓存 调度 数据库
Python中的定时器用法:Timer定时器和schedule库
Python中的定时器用法:Timer定时器和schedule库
289 0
|
4月前
|
测试技术 PHP
Swoole 源码分析之 Timer 定时器模块
Swoole 中的毫秒精度的定时器。底层基于 `epoll_wait` 和 `setitimer` 实现,数据结构使用最小堆,可支持添加大量定时器。
75 0
Swoole 源码分析之 Timer 定时器模块
|
6月前
|
API
FreeRTOS软件定时器的原理以及使用实例
FreeRTOS软件定时器的原理以及使用实例
133 0
|
6月前
|
缓存
muduo源码剖析之Timer定时器
Timer 类是 muduo 网络库中的一个定时器类,用于在指定的时间间隔后执行某个任务。Timer 类提供了一系列的方法来创建、启动、停止和删除定时器,以及设置定时器的时间间隔和回调函数等。在 muduo 网络库中,Timer 类被广泛应用于各种网络任务中,例如定期发送心跳包、更新缓存、清理资源等。通过使用 Timer 类,我们可以方便地实现定时任务,提高网络应用程序的可靠性和稳定性。:启动定时器,在指定的时间间隔后调用回调函数。:停止定时器,不再执行定时任务。
110 0
|
6月前
|
缓存 前端开发 NoSQL
muduo异步日志库模块的实现
muduo异步日志库模块的实现
|
Java 调度
架构系列——定时任务中的Timer类使用简析
架构系列——定时任务中的Timer类使用简析
|
资源调度 API
[Nestjs] 集成定时器以及使用方法
在后台开发中,我们经常遇到定时的需求,比如每天早上八点推送日志,推送待办,推送天气预报等。接下来简单介绍Nestjs集成定时器的简单使用方法!
302 0
|
Java 测试技术
在多线程中自定义实现定时器(Timer)
在多线程中自定义实现定时器(Timer)
|
存储 开发工具 数据安全/隐私保护
乾坤大挪移,如何将同步阻塞(sync)三方库包转换为异步非阻塞(async)模式?Python3.10实现。
众所周知,异步并发编程可以帮助程序更好地处理阻塞操作,比如网络 IO 操作或文件 IO 操作,避免因等待这些操作完成而导致程序卡住的情况。云存储文件传输场景正好包含网络 IO 操作和文件 IO 操作,比如业内相对著名的七牛云存储,官方sdk的默认阻塞传输模式虽然差强人意,但未免有些循规蹈矩,不够锐意创新。在全球同性交友网站Github上找了一圈,也没有找到异步版本,那么本次我们来自己动手将同步阻塞版本改造为异步非阻塞版本,并上传至Python官方库。
乾坤大挪移,如何将同步阻塞(sync)三方库包转换为异步非阻塞(async)模式?Python3.10实现。