第13章 网络 Page724 asio定时器

本文详细解释了在Asio库中如何使用io_service进行异步定时任务的设置和回调,涉及定时器与ios_service的关联、定时任务的提交与操作系统处理、以及回调动作的触发机制。重点强调了run()方法的作用和回调活动的异步性质。
摘要由CSDN通过智能技术生成

 程序代码:

11行,声明一个ios对象

13行,使用ios对象作为参数声明一个定时器,此时,定时器和ios完成了关联,后面定时器如果有任务的话,就可以将任务交给ios

16行,为定时器设置一个定时任务,13行,定时器已经和ios已经了关联,定时器就可以将定时工作交给ios,定时工作由操作系统完成,所以这一行实际上,是将任务添加到io_service身上,因为这个定时任务,是由操作系统完成的。将任务添加到io_service身上,并不需要ios“转”起来

23~33行,使用定时器的async_wait()方法,为定时器设置一个回调动作(函数指针,函数对象,Lambda表达式,std::function对象都可以),当定时器的定时任务由ios完成以后(操作系统完成),操作系统则“吐”出一个事件给ios,告诉ios,定时任务完成了,你可以发起回调动作了, 如果ios空闲,并且ios的run()方法正在被调用,则ios处理此事件,发起回调动作,就是本例中Lamabda表达式。

37行,启动io_service服务,定时器定时任务由ios交给操作系统完成后,操作系统回馈给ios一个事件,通知ios任务已经完成,ios接收到此事件,便会发起回调动作。启动定时器的回调活动(async_wait()函数的参数)。若被注释掉,则定时任务完成后,不会启动回调活动。

综合起来,过程是这样的,13行,完成定时器与ios的关联,16行,为定时器设置一个任务,这个任务会被ios交给操作系统完成(这一步不需要ios“转”起来),操作系统完成任务完成后,回馈一个事件给ios, 通知ios,任务已经完成了,可以发起回调了,37行,如果ios的run()方法已经调用了,则,ios将发起回调动作,就是执行23行(设置一个回调动作)的Lambda表达式。

ios_service

ios_service(输入输出_服务),在asio新版中也叫io_context(输入输出_上下文)。更好的名称应是“io_engine(输入输出_引擎)”;run一词,不能简单地认为是有个小人在跑,而是要想到"运转"这个词。

本文中的程序第16行,就是往ios_service身上丢个定时任务

当我们调用io_service的run()方法,引擎的齿轮就转了起来,然后需要说三遍的重要事情来了:io_service对象的run()方法并非永久地转下去,它只是转到没有任务就立即停转(函数返回)

当io_service对象“转”起来(即run()方法正在执行),它就会去处理身上的事件当全部任务的全部事件都处理完成,该io_service对象就不再转动。后续要是又有新任务往它身上加,除非再次调用run(),否则任务都不会被执行,最终也许任务堆积成山。

任务来自何处?任务谁来完成?任务去往何处?

一、任务来自何处?

任务来自应用程序,比如我们写的代码:

timer_1.async_wait(...); 

timer_1在执行async_wait()方法时,创建了一个异步任务,并且将该任务交给io_service对象,即本例中的ios变量timer_1什么时候认识的ios对象的呢?请看它的构造过程:

boost::asio::system_timer timer_1(ios);

time_1是一个对象,它拥有一件有赖外部环境推动完成的任务这样的对象在asio中称为“I/O对象”。比如说“定时器”,之前在“异步、异步、异步”小节中演示了两种实现方法:一是当前应用程序的当前线程直接堵塞“睡”上一段时间,二是当前应用程序新开一个线程,让那个线程“睡上”上一段时间。尽管后者的表现效果是"异步",但与前者没有本质区别,因为在等待事情完成的期间,都百分百地耗费当前应用程序的一个线程。asio提供的timer,则将定时的工作交给操作系统或特定支撑框架,因为底层往往可以提供低成本的定时器实现。

小提示:定时器和“I/O”有关系吗?

可以这样理解,我们交个操作系统一个时长,经过该时长后,操作系统回馈一个信号以示“定时到啦”,这一进一出不就是“I/O”?

二、任务谁来完成?

答:任务本例中为定时工作被io_service交给操作系统完成

三、任务去往何处?

答:任务完成后就结束使命了,但为了让上层应用程序知道任务完成了,io_service对象会触发一个事件。事件就是创建任务时指定的回调动作,比如本例中timer_1.async_wait(...)调用时入参所指定的lambda表达式。因此可以理解为任务走了,事件来了。当然,前提是有线程在调用该io_service对象的run()方法

现在,关于io_service的图示如图13-18所示

任务交给操作系统之后,线程就空闲了,可以去处理别的任务。而操作系统完成任务后将“吐”出事件给某个io_service对象,此时如果有一个线程正好在运行该io_service对象的run()方法,并且它空闲(没有在处理之前的事件),它就有机会接收并处理该事件。如果这样的线程有多个,asio保障只会有一个线程接收并处理同一个事件。如果没有任何这样的线程,新事件就会无人受理。

程序的调试

若我们在第25行打一个断点,则会发现,调试启动以后,程序并不会立即停在第25行,而是在定时器任务完成之后,触发回调活动,程序才会停在第25行,这充分说明,回调活动是异步执行的

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值