boost io_service,boost asio 多线程
Boost.asio(定时器、线程、io_service类)的简单使用-简单日志-网易博客
Boost.asio(定时器、线程、io_service类)的简单使用
分类:
碳碳升压
标签:
字号、大、中、小订阅
2.同步定时器这一章介绍了asio如何在定时器上执行阻塞等待。
实现中,我们包含了必要的头文件。
所有的asio类都可以简单地通过include asio.hpp 来调用。
#包含IOStream #包含BOOST/ASIO。HPP另外,这个例子使用了timer,我们还包含了Boost的头文件。Date_Time控制时间。
#包含BOOST/DATE _ TIME/POSIX _ TIME/POSIX _ TIME。HPP至少需要一个Boost: asio: IO _ SERVICE对象才能使用asio。这个类提供了访问I/O的函数,首先我们在main函数中声明。
int main(){ boost:asio:io _ service io;接下来,我们声明boost:asio:deadline_timer对象。asio的这个核心类提供了I/O函数(这里更具体地说是定时函数),并且总是以一个io_service对象作为它的第一个构造函数,而第二个构造函数的参数将定时器设置为5秒后过期。
boost:asio:deadline _ timer t(io,boost:POSIX _ time:seconds(5));在这个简单的例子中,我们演示了计时器上的阻塞等待。也就是说,调用Boost:ASIO:Deadline _ timer:wait()的定时器在创建后5秒内定时器到达之前不会返回值(注意:不是等待开始之后)。
一个deadline_timer只有两种状态:到达的时候,没有到达的时候。
如果当时在timer对象上调用了boost:ASIO:deadline _ timer:wait(),它会立即返回。
t . wait();最后,我们输出“你好,世界!”理所当然。让我们演示一下计时器。是时候了。
你好,世界!返回0;}完整代码:# includeiostrem # include boost/asio . HPP # include boost/date _ time/POSIX _ time/POSIX _ time . hppinmain(){ boost:asio:io _ service io;boost:asio:deadline _ timer t(io,boost:POSIX _ time:seconds(5));t . wait();你好,世界!返回0;}
3.异步计时器# include iostream # include asio . HPP # include boost/date _ time/POSIX _ time/POSIX _ time。hppasio的异步函数将在异步操作完成后被回调。这里我们定义一个将被回调的函数。
void print(const asio:error/* e */){ STD:cout Hello,world!;} int main(){ asio:io _ service io;asio:deadline_timer t(io,boost:POSIX _ time:seconds(5));这里我们调用asio:deadline _ timer:async _ wait()异步等待。
t.async_wait(打印);最后我们还要调用asio:io_service:run()。
asio库只会调用正在运行的asio:io_service:run()的回调函数。
如果没有调用asio:io_service:run(),那么回调永远不会发生。
Asio:io_service:run()会一直工作到,这里是计时器。当计时器到达时,回调完成。
在调用asio:io_service:run()之前,不要忘记设置io_service的任务。比如这里,如果我们忘记先调用ASIO:deadline _ timer:async _ wait(),asio:io_service:run()会瞬间返回。
io . run();返回0;}完整代码:# includeiosteram # include asio . HPP # include boot/date _ time/POSIX _ time/POSIX _ time . HPP void print(consta SiO:error/* e */){ STD:cout hello,world!;} int main(){ asio:io _ service io;asio:deadline_timer t(io,boost:POSIX _ time:seconds(5));t.async_wait(打印);io . run();返回0;}
4.回调函数的参数在这里,我们将每秒回调一次来演示如何回调函数参数的意义。
# includeiostrem # include asio . HPP # include boost/bind . HPP # include boost/date _ time/POSIX _ time/POSIX _ time . HPP首先,调整定时器的持续时间,启动异步等待。说明回调函数需要访问定时器才能周期性运行,所以我们会引入两个新参数。
指向timer的指针an int*指向计数器void print(const asio:error/* e */,asio: deadline _ timer * t,int * count){我们打算让这个函数运行6个周期,但是,你会发现这里没有明确的终止io_service的方法。但是,回过头来看上一节,你会发现,当asio:io_service:run()会在所有任务完成后终止。这样,当计算器的值达到5 (0是第一次运行的值)时,我们就不会开始新的异步等待。
if(* count 5){ STD:cout * count " ";(*计数);然后,我们推迟的计时器的终止时间。通过在原先的终止时间上增加延时,我们可以确保计时器不会在处理回调函数所需时间内的到期。
(原文:通过计算相对于旧到期时间的新到期时间,我们可以确保计时器不会由于处理处理程序中的任何延迟而偏离整秒标记。)
t-expires _ at(t-expires _ at()boost:POSIX _ time:seconds(1));然后我们开始一个新的同步等待。如您所见,我们用把打印和他的多个参数用升压:绑定函数合成一个的形为void(const asio:error)回调函数(准确的说是功能对象)。
在这个例子中,升压:绑定的asio:占位符:错误参数是为了给回调函数传入一个错误对象。当进行一个异步操作,开始升压:绑定时,你需要使用它来匹配回调函数的参数表。下一节中你会学到回调函数不需要错误参数时可以省略它。
t- async_wait(boost:bind(print,asio:占位符*误差,t,计数));} } int main(){ asio:io _ service io;int count=0;asio:deadline_timer t(io,boost:POSIX _ time:seconds(1));和上面一样,我们再一次使用了绑定asio:deadline _ timer:async _ wait()
t.async_wait(boost:bind(print,asio:占位符*误差,t,计数));io。run();在结尾,我们打印出的最后一次没有设置计时器的调用的数数的值
" std:cout "的最终计数为”计数”;返回0;} 完整的代码:# include iostream # include asio。HPP #包含增强/绑定。HPP #包括增强/日期时间/位置时间/位置时间。HPP void print(const asio:error/* e */,bspasio:deadline_timer* t,int * count){ if(* count 5){ STD:cout * count " ";(*计数);t-expires _ at(t-expires _ at()boost:POSIX _ time:seconds(1));t- async_wait(boost:bind(print,asio:占位符*误差,t,计数));} } int main(){ asio:io _ service io;int count=0;asio:deadline_timer t(io,boost:POSIX _ time:seconds(1));t.async_wait(boost:bind(print,asio:占位符*误差,t,计数));io。run();" std:cout "的最终计数为”计数”;返回0;}
5.成员函数作为回调函数本例的运行结果和上一节类似
#包含iostream #包含boost/asio。HPP #包含增强/绑定。HPP #包括增强/日期时间/位置时间/位置时间。HPP我们先定义一个打印机类
类打印机{ public: //构造函数有一个io _服务参数,并且在初始化计时器_时用到了它。用来计数的计数_这里同样作为了成员变量printer(boost:asio:io _ service io):timer _(io,boost:posix_time:seconds(1)),count_(0) { boost:bind同样可以出色的工作在成员函数上。众所周知,所有的非静态成员函数都有一个隐式的这参数,我们需要把这作为参数约束到成员函数上。和上一节类似,我们再次用约束构造出无效(常数boost:asio:错误)形式的函数。
注意,这里没有指定boost:asio:占位符:错误占位符,因为这个打印成员函数没有接受一个错误对象作为参数。
计时器_ .async _ wait(boost:bind(printer:print,this));在类的折构函数中我们输出最后一次回调的数数的值
~printer() { std:cout 最终计数为count _ ;}
打印函数于上一节的十分类似,但是用成员变量取代了参数。
void print(){ if(count _ 5){ STD:cout count _ ;count _;计时器_ .expires_at(计时器_。expires _ at()boost:POSIX _ time:seconds(1));计时器_ .async _ wait(boost:bind(printer:print,this));} } private:boost:asio:deadline _ timer timer _;int count _;};现在主要的函数清爽多了,在运行io _服务之前只需要简单的定义一个打印机对象。
int main(){ boost:asio:io _ service io;打印机p(io);io。run();返回0;} 完整的代码:#包含iostream #包含boost/asio。HPP #包含增强/绑定。HPP #包括增强/日期时间/位置时间/位置时间。HPP类printer { public:printer(boost:asio:io _ service io):timer _(io,boost:posix_time:seconds(1)),count_(0) { timer_ .async _ wait(boost:bind(printer:print,this));} ~printer() { std:cout 最终计数为count _ ;} void print(){ if(count _ 5){ STD:cout count _ ;count _;计时器_ .expires_at(计时器_。expires _ at()boost:POSIX _ time:seconds(1));计时器_ .async _ wait(boost:bind(printer:print,this));} } private:boost:asio:deadline _ timer timer _;int count _;};int main(){ boost:asio:io _ service io;打印机p(io);io。run();返回0;}
6.多线程回调同步本节演示了使用boost:asio:strand在多线程程序中进行回调同步(同步)。
先前的几节阐明了如何在单线程程序中用boost:asio:io_service:run()进行同步。如您所见、asio库确保仅当当前线程调用boost:asio:io_service:run()时产生回调。显然,仅在一个线程中调用boost:asio:io_service:run()来确保回调是适用于并发编程的。
一个基于澳洲安全情报局的程序最好是从单线程入手,但是单线程有如下的限制,这一点在服务器上尤其明显:
当回调耗时较长时,反应迟钝。在多核的系统上无能为力如果你发觉你陷入了这种困扰,可以替代的方法是建立一个boost:asio:io_service:run()的线程池。然而这样就允许回调函数并发执行。所以,当回调函数需要访问一个共享,线程不安全的资源时,我们需要一种方式来同步操作。
#包含iostream #包含boost/asio。HPP #包含增强/线程。HPP #包含增强/绑定。HPP #包括增强/日期时间/位置时间/位置时间。HPP在上一节的基础上我们定义一个打印机类,此次,它将并行运行两个计时器
类打印机{公共:除了声明了一对boost:asio:deadline_timer,构造函数也初始化了类型为boost:asio:strand的strand_成员。
boost:asio:strand可以分配的回调函数。它保证无论有多少线程调用了boost:asio:io_service:run(),下一个回调函数仅在前一个回调函数完成后开始,当然回调函数仍然可以和那些不使用boost:asio:strand分配,或是使用另一个boost:asio:strand分配的回调函数一起并发执行。
printer(boost:asio:io _ service io):strand _(io),timer1_(io,boost:posix_time:seconds(1)),timer2_(io,boost:posix_time:seconds(1)),count_(0) {当一个异步操作开始时,用boost:asio:strand来包装(包装)回调函数boost:asio:strand:wrap()会返回一个由boost:asio:strand分配的新的处理程序(句柄),这样,我们可以确保它们不会同时运行。
定时器1_。async_wait(strand_ .wrap(boost:bind(printer:print 1,this));定时器2_。async_wait(strand_ .wrap(boost:bind(printer:print 2,this));} ~printer() { std:cout 最终计数为count _ ;}
多线程程序中,回调函数在访问共享资源前需要同步。这里共享资源是标准* cout和计数_变量。
void print 1(){ if(count _ 10){ STD:cout Timer 1: count _ ;count _;定时器1_。expires_at(定时器1_。expires _ at()boost:POSIX _ time:seconds(1));定时器1_。async_wait(strand_ .wrap(boost:bind(printer:print 1,this));} } void print 2(){ if(count _ 10){ STD:cout Timer 2: count _ ;count _;定时器2_。expires_at(定时器2_。expires _ at()boost:POSIX _ time:seconds(1));定时器2_。async_wait(strand_ .wrap(boost:bind(printer:print 2,this));} } private:boost:asio:strand strand _;boost:asio:deadline _定时器定时器1 _;boost:asio:deadline _定时器定时器2 _;int count _;};主要的函数中boost:asio:io_service:run()在两个线程中被调用:主线程、一个升压:线程线程。
正如单线程中那样,并发的boost:asio:io_service:run()会一直运行直到完成任务。后台的线程将在所有异步线程完成后终结。
int main(){ boost:asio:io _ service io;打印机p(io);boost:thread t(boost:bind(boost:asio:io _ service:run,io));io。run();t . join();返回0;} 完整的代码:#包含iostream #包含boost/asio。HPP #包含增强/线程。HPP #包含增强/绑定。HPP #包括增强/日期时间/位置时间/位置时间。HPP类printer { public:printer(boost:asio:io _ service io):strand _(io)、timer1_(io,boost:posix_time:seconds(1))、timer2_(io,boost:posix_time:seconds(1))、count_(0) { timer1_ .async_wait(strand_ .wrap(boost:bind(printer:print 1,this));定时器2_。async_wait(strand_ .wrap(boost:bind(printer:print 2,this));} ~printer() { std:cout 最终计数为count _ ;} void print 1(){ if(count _ 10){ STD:cout Timer 1: count _ ;count _;定时器1_。expires_at(定时器1_。expires _ at()boost:POSIX _ time:seconds(1));定时器1_。async_wait(strand_ .wrap(boost:bind(printer:print 1,this));} } void print 2(){ if(count _ 10){ STD:cout Timer 2: count _ ;count _;定时器2_。expires_at(定时器2_。expires _ at()boost:POSIX _ time:seconds(1));定时器2_。async_wait(strand_ .wrap(boost:bind(printer:print 2,this));} } private:boost:asio:strand strand _;boost:asio:deadline _定时器定时器1 _;boost:asio:deadline _定时器定时器2 _;int count _;};int main(){ boost:asio:io _ service io;打印机p(io);boost:thread t(boost:bind(boost:asio:io _ service:run,io));io。run();t . join();返回0;}
7.三氯苯酚客户端:对准时间#包含iostream #包含升压/阵列。HPP #包含boost/asio.hpp本程序的目的是访问一个时间同步服务器,我们需要用户指定一个服务器(如time-nw.nist.gov),用互联网协议(互联网协议)亦可。
(译者注:日期查询协议,这种时间传输协议不指定固定的传输格式,只要求按照美国信息交换标准代码标准发送数据。使用boost:asio:IP:TCP;int main(int argc,char* argv[]) { try { if (argc!=2) { std:cerr 用法:客户端主机STD:endl;返回1;} 用澳洲安全情报局进行网络连接至少需要一个boost:asio:io_service对象boost:asio:io _ service io _ service;
我们需要把在命令行参数中指定的服务器转换为三氯苯酚上的节点。完成这项工作需要boost:asio:ip:tcp:解析器对象tcp:解析程序解析器(io _ service);
一个分解器对象查询一个参数,并将其转换为三氯苯酚上节点的列表。这里我们把argv[1]中的切断的名字和要查询字串白天关联tcp:resolver:query查询(argv[1],‘白天’);
节点列表可以用boost:asio:IP:TCP:resolver:iterator来进行迭代。迭代程序默认的构造函数生成一个结束迭代器。TCP:resolver:iterator endpoint _ iterator=resolver。解决(查询);tcp:解析器:迭代器结束;现在我们建立一个连接的索科特,由于获得节点既有IPv4也有IPv6的。所以,我们需要依次尝试他们直到找到一个可以正常工作的。这步使得我们的程序独立于互联网协议(互联网协议)版本tcp:套接字套接字(io _ service);boost:asio:error error=boost:asio:error:host _ not _ found;而(错误端点_迭代器!=end){ socket。close();插座。connect(* endpoint _ iterator,boost:asio:assign _ error(error));} if(错误)抛出错误;连接完成,我们需要做的是读取白天服务器的响应。
我们用升压:数组来保存得到的数据,boost:asio:buffer()会自动根据排列的大小暂停工作,来防止缓冲溢出。除了使用升压:数组,也可以使用char []或STD:矢量。for(;){ boost:array char,128 bufboost:asio:错误错误;size _ t len=socket。read _ some(boost:asio:buff(buf),boost:asio:assign _ error(error));当服务器关闭连接时,boost:asio:IP:TCP:socket:read _ some()会用boost:asio:error:eof标志完成,这时我们应该退出读取循环了. if(error==boost:asio:error:eof)break;//对等方完全关闭了连接elseif(错误)抛出错误;//其他一些错误std:cout.write(buf.data(),len);如果发生了什么异常我们同样会抛出它} catch(STD:exception e){ STD:cerr e . what()STD:endl;}
运行示例:在软件的煤矿管理局窗口下
输入:upload.exetime-a.nist.gov输出:54031 06-10-23 01:50:45 07 0 0 454.2世界协调时(NIST) *
完整的代码:# include iostream # include boost/array。HPP #包括意大利空间情报组织。HPP使用asio:IP:TCP;int main(int argc,char* argv[]) { try { if (argc!=2) { std:cerr 用法:客户端主机STD:endl;返回1;} asio:io _ service io _ service;tcp:解析程序解析器(io _ service);tcp:解析程序:查询查询(argv[1],‘白天’);TCP:resolver:iterator endpoint _ iterator=resolver。解决(查询);tcp:解析器:迭代器结束;tcp:套接字套接字(io _ service);asio:error error=asio:error:host _ not _ found;而(错误端点_迭代器!=end){ socket。close();插座。connect(* endpoint _ iterator,asio:assign _ error(error));} if(错误)抛出错误;for(;){ boost:array char,128 bufasio:error错误;size _ t len=socket。read _ some(asio:buff(buf),asio:assign _ error(error));if(error==asio:error:eof)break;//对等方完全关闭了连接elseif(错误)抛出错误;//其他一些错误std:cout.write(buf.data(),len);} } catch(STD:exception e){ STD:cerr e . what()STD:endl;}返回0;}
8.三氯苯酚同步时间服务器# include ctime # include iostream # include字符串# include asio。HPP使用asio:IP:TCP;我们先定义一个函数返回当前的时间的线形式。这个函数会在我们所有的时间服务器示例上被使用STD:string make _ daytime _ string(){使用命名空间STD;//对于time_t,时间和ctime time _ t now=time(0);返回ctime(现在);} int main(){ try { asio:io _ service io _ service;新建一个asio:ip:tcp:接受器对象来监听新的连接。我们监听三氯苯酚端口13、知识产权版本为v4tcp:acceptor acceptor(io _ service,tcp:endpoint(tcp:v4(),13));
这是一个迭代服务器,也就是说同一时间只能处理一个连接。建立一个窝来表示一个和客户端的连接,然后等待客户端的连接对于(;){ TCP:socket socket(io _ service);接受者套接字);当客户端访问服务器时,我们获取当前时间,然后返回它STD:string message=make _ daytime _ string();asio:write(socket,asio:buffer(message),asio:transfer_all(),asio:ignore _ error());} } 最后处理异常catch(STD:exception e){ STD:cerr e . what()STD:endl;}返回0;运行示例:运行服务器,然后运行上一节的客户端,在软件的煤矿管理局窗口下
输入:客户端. exe
输出:2006年10月23日星期一完整的代码:# include ctime # include iostream # include string # include asio。HPP使用asio:IP:TCP;STD:string make _ daytime _ string(){使用命名空间STD;//对于time_t,时间和ctime time _ t now=time(0);返回ctime(现在);} int main(){ try { asio:io _ service io _ service;TCP:acceptor acceptor(io _ service,tcp:endpoint(tcp:v4(),13));for(;){ TCP:socket socket(io _ service);接受者套接字);STD:string message=make _ daytime _ string();asio:write(socket,asio:buffer(message),asio:transfer_all(),asio:ignore _ error());} } catch(STD:exception e){ STD:cerr e . what()STD:endl;}返回0;}
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。