Boost.Asio 是一个用于网络和低级 I/O 编程的跨平台 C++ 库,它使用现代 C++ 方法为开发人员提供一致的异步模型


一个异步使用计时器的样例

#include <iostream>
#include <boost/asio.hpp> void print(const boost::system::error_code & /* e */)
{
std::cout <<“hello world!” << std::endl;
} int main()
{
boost :: asio :: io_context me; // 提供对 i/o 功能的访问
boost :: asio :: steady_timer t(io,boost :: asio :: chrono :: seconds(5));
t.async_wait(print); // 插入回调函数
io.run(); return;
}

asio 库提供了一种保证,即只能从当前调用 io_context::run() 的线程调用回调处理程序

io_context::run() 函数将继续运行,它的工作是计时器上的异步等待,在计时器到期并且回调完成之前调用不会返回

在调用 io_context::run() 前需要给 io_context 设定一些工作,如果省略了 t.async_wait(print); 的调用,io_context::run() 将立刻返回

 

多次触发计时器

要实现重复计时器,需要在回调函数中更改计时器的到期时间,然后启动新的异步等待

设定计时器将在第 6 次触发时停止程序

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp> // 增加指向计时器对象的指针以访问计时器对象,以及一个计数器 count
void print(const boost::system::error_code & /*e*/,
boost::asio::steady_timer * t, int * count)
{
// 这里没有明确的调用要求 io_context 停止,而是通过 count == 5 时不再对计时器启动新的异步等待,io_context 将结束工作并停止运行
if (*count < 5)
{
std::cout << *count << std::endl;
++(*count);
// 将计时器到期时间向后延时 1 秒
t->expires_at(t->expiry() + boost::asio::chrono::seconds(1));
// 启动一个新的异步等待,使用 boost::bind 使需要指定与回调函数参数列表相匹配的参数
t->async_wait(boost::bind(print,
boost::asio::placeholders::error, t, count));
}
} int main()
{
boost::asio::io_context io;
int count = 0;
boost::asio::steady_timer t(io, boost::asio::chrono::seconds(1));
t.async_wait(boost::bind(print,
boost::asio::placeholders::error, &t, &count)); io.run();
std::cout << "Final count is " << count << std::endl; return 0;
}

 

使用类的成员函数作回调处理

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp> class printer
{
public:
// 构造时引用 io_context 对象,使用它初始化 timer
printer(boost::asio::io_context& io)
: timer_(io, boost::asio::chrono::seconds(1)),
count_(0)
{
// 使用 bind 绑定当前对象的 this 指针,利用成员 count 控制计时器的执行
timer_.async_wait(boost::bind(&printer::print, this));
} // 在析构中打印结果
~printer()
{
std::cout << "Final count is " << count_ << std::endl;
} // 作为类的成员函数,无需再传入参数,直接使用当前对象的成员变量
void print()
{
if (count_ < 5)
{
std::cout << count_ << std::endl;
++count_; timer_.expires_at(timer_.expiry() + boost::asio::chrono::seconds(1));
timer_.async_wait(boost::bind(&printer::print, this));
}
} private:
boost::asio::steady_timer timer_;
int count_;
}; int main()
{
// main 里的调用简单了很多
boost::asio::io_context io;
printer p(io);
io.run(); return 0;
}

 

多线程中的回调函数同步

asio 库提供了一种保证,即只能从当前调用 io_context::run() 的线程调用回调函数。因此,仅从一个线程调用 io_context::run() 回调函数无法并发运行

这里需要使用 io_context::strand 来控制分配 handler 的执行,它可以保证无论 io_context::run() 的线程有多少,同时只能有一个 handler 程序执行,保证了共享资源的线程安全

在本例中 handler (print1 / print2) 所访问的共享资源包括 std::cout 和成员变量 count_

#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp> class printer
{
public:
printer(boost::asio::io_context& io)
: strand_(io), // strand 成员,用于控制 handler 的执行
timer1_(io, boost::asio::chrono::seconds(1)), // 运行两个计时器
timer2_(io, boost::asio::chrono::seconds(1)),
count_(0)
{
// 启动异步操作时,每个 handler 都绑定到 strand 对象
// bind_executor() 返回一个新的 handler,它将自动调度其包含的 printer::print1
// 通过将 handler 绑定到同一个 strand,保证它不会同时执行
timer1_.async_wait(boost::asio::bind_executor(strand_,
boost::bind(&printer::print1, this))); timer2_.async_wait(boost::asio::bind_executor(strand_,
boost::bind(&printer::print2, this)));
} ~printer()
{
std::cout << "Final count is " << count_ << std::endl;
} void print1()
{
if (count_ < 10)
{
std::cout << "Timer 1: " << count_ << std::endl;
++count_; timer1_.expires_at(timer1_.expiry() + boost::asio::chrono::seconds(1)); timer1_.async_wait(boost::asio::bind_executor(strand_,
boost::bind(&printer::print1, this)));
}
} void print2()
{
if (count_ < 10)
{
std::cout << "Timer 2: " << count_ << std::endl;
++count_; timer2_.expires_at(timer2_.expiry() + boost::asio::chrono::seconds(1)); timer2_.async_wait(boost::asio::bind_executor(strand_,
boost::bind(&printer::print2, this)));
}
} private:
boost::asio::io_context::strand strand_;
boost::asio::steady_timer timer1_;
boost::asio::steady_timer timer2_;
int count_;
}; int main()
{
boost::asio::io_context io;
printer p(io);
// main 函数现在有两个线程调用 io_context::run(),主线程和由 boost::thread 对象执行的额外线程
boost::thread t(boost::bind(&boost::asio::io_context::run, &io));
io.run();
t.join(); return 0;
}

 


参考:

Boost.Asio

How strands work and why you should use them

C++ 异步编程:Boost.Asio的更多相关文章

  1. Boost.Asio c++ 网络编程翻译(21)

    同步VS异步 Boost.Asio的作者做了一个非常惊艳的工作:它能够让你在同步和异步中自由选择,从而更好的适应你的应用. 在之前的章节中,我们学习了每种类型应用的框架,比方同步client,同步服务 ...

  2. boost::asio译文

        Christopher Kohlhoff Copyright © 2003-2012 Christopher M. Kohlhoff 以Boost1.0的软件授权进行发布(见附带的LICENS ...

  3. Boost.Asio技术文档

    Christopher Kohlhoff Copyright © 2003-2012 Christopher M. Kohlhoff 以Boost1.0的软件授权进行发布(见附带的LICENSE_1_ ...

  4. Boost.Asio的使用技巧

    基本概念 Asio proactor I/O服务 work类 run() vs poll() stop() post() vs dispatch() buffer类 缓冲区管理 I/O对象 socke ...

  5. boost::asio学习(定时器)

    #include <boost/asio.hpp> #include <iostream> void handle1(const boost::system::error_co ...

  6. boost.asio系列(一)——deadline_timer

    一.构造函数 一个deadline_timer只维护一个超时时间,一个deadline_timer不同时维护多个定时器.在构造deadline_timer时指定时间: basic_deadline_t ...

  7. Boost.Asio基础(五) 异步编程初探

    异步编程 本节深入讨论异步编程将遇到的若干问题.建议多次阅读,以便吃透这一节的内容,这一节是对整个boost.asio来说是非常重要的. 为什么须要异步 如前所述,通常同步编程要比异步编程更简单.同步 ...

  8. Boost.Asio c++ 网络编程翻译(20)

    异步服务端 这个图表是相当复杂的:从Boost.Asio出来你能够看到4个箭头指向on_accept.on_read,on_write和on_check_ping. 着也就意味着你永远不知道哪个异步调 ...

  9. boost::asio 的同、异步方式

    转自:http://blog.csdn.net/zhuky/archive/2010/03/10/5364574.aspx Boost.Asio是一个跨平台的网络及底层IO的C++编程库,它使用现代C ...

随机推荐

  1. NumPyArray

    import arcpy import numpy # Create a simple array from scratch using random values myArray = numpy.r ...

  2. elasticsearch使用BulkProcessor批量入库数据

    在解决es入库问题上,之前使用过rest方式,经过一段时间的测试发现千万级别的数据会存在10至上百条数据的丢失问题, 在需要保证数据的准确性的场景下,rest方式并不能保证结果的准确性,因此采用了el ...

  3. SQL中join和cross join的区别

    SQL中的连接可以分为内连接,外连接,以及交叉连接 . 1. 交叉连接CROSS JOIN 如果不带WHERE条件子句,它将会返回被连接的两个表的笛卡尔积,返回结果的行数等于两个表行数的乘积: 举例, ...

  4. [English]常用中英文对照表

    Always have been 一直如此 accordingly:相应地 assumption:假定 brace:大括号 branket:中括号 comma:逗号MISC:Miscellaneous ...

  5. Git 代码撤销、回滚到任意版本(当误提代码到本地或master分支时)

    转自https://www.cnblogs.com/lwh-note/p/9639835.html 两种情况(场景) 情况一      代码还只在本地,未push到运程仓库,想把代码还原到上一次com ...

  6. Spring cloud微服务安全实战-3-13重构代码

    让代码同时支持两种方式,登陆访问和带着请求头的token访问也可以. 首先做代码的重构 这里改成getSession() 改成这样以后会有一个问题,我用httpBasic登陆成功以后,我的用户信息放在 ...

  7. javaselenium遇到的问题和解决方法(还没试,遇到问题可以先看这里)

    Firefox路径问题 firefox火狐浏览器去完成自动化测试时,代码报了如下错误: Cannot find firefox binary in PATH. mark sure firefox is ...

  8. 宣化上人:大佛顶首楞严经四种清净明诲浅释(4-5)(转自学佛网:http://www.xuefo.net/nr/article23/230699.html)

    大佛顶首楞严经四种清净明诲浅释(4) 唐天竺·沙门般剌密帝译 宣化上人主讲 一九八三年四月十七日晚讲于万佛圣城 汝教世人修三摩地.先断心淫.是名如来.先佛世尊.第一决定清净明诲. 所以说,教人这个爱的 ...

  9. 转Python 爬虫入门实战

    转自:https://www.cnblogs.com/babycomeon/p/11651888.html

  10. HTML布局排版2 div的和图片平铺方便管理

    在HTML里,由于浏览器显示器等差异,浏览器的宽度也会有变化,为了适应不同的宽度,需要用到平铺.例如页面前面的固定的条等,如果是纯色,可以用背景色,如果不是纯色,是渐变等,可以用条状图平铺.常见的布局 ...