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 定时器