ASIO库介绍
a cross-platform C++ library for network。
Asio 是一个好用的、常用的跨平台的 C++ 库,常用于网络编程、底层的 I/O 编程等 (low-level I/O)。结构框架如下:
分为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; }); }
引用:
Windows10下配置Boost_卖萌的大米的博客-CSDN博客_boost windows
vcpkg使用详解_weixin_34293246的博客-CSDN博客
vcpkg 详细介绍_零点零一的博客-CSDN博客_vcpkg是什么
基于Asio 的定时器( asio::steady_timer )_万里归来少年心的博客-CSDN博客_asio 定时器