当前位置: 首页 > 编程日记 > 正文

libev源码解析——定时器原理

本文将回答《libev源码解析——I/O模型》中抛出的两个问题。(转载请指明出于breaksoftware的csdn博客)

对于问题1:为什么backend_poll函数需要指定超时?我们让其一直等待到有事件发生不是更好么?

答案是“必须要指定超时”。为什么呢?在《libev源码解析——总览》中,我们抛出过一个问题:定时器和事件是如何关联的?因为libev是一个事件库,所以我们需要将定时器的逻辑也转换成事件相关操作。

我们看下其实现原理。libev在初始化默认循环时调用了ev_default_loop方法,其会在底层调用evpipe_init方法。它会通过eventfd创建一个永远等不到的事件。这样我们就可以调整等待该事件的超时时间来达到定时执行的目的。

static void noinline ecb_cold
evpipe_init (EV_P)
{if (!ev_is_active (&pipe_w)){int fds [2];# if EV_USE_EVENTFDfds [0] = -1;fds [1] = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);if (fds [1] < 0 && errno == EINVAL)fds [1] = eventfd (0, 0);if (fds [1] < 0)
# endif{while (pipe (fds))ev_syserr ("(libev) error creating signal/async pipe");fd_intern (fds [0]);}evpipe [0] = fds [0];if (evpipe [1] < 0)evpipe [1] = fds [1]; /* first call, set write fd */else{/* on subsequent calls, do not change evpipe [1] *//* so that evpipe_write can always rely on its value. *//* this branch does not do anything sensible on windows, *//* so must not be executed on windows */dup2 (fds [1], evpipe [1]);close (fds [1]);}fd_intern (evpipe [1]);ev_io_set (&pipe_w, evpipe [0] < 0 ? evpipe [1] : evpipe [0], EV_READ);ev_io_start (EV_A_ &pipe_w);ev_unref (EV_A); /* watcher should not keep loop alive */}
}

因为定时器并非是由事件触发而执行,而是由于事件没有触发导致等待超时而执行。所以backend_poll函数指针调用时,不可以一直等待下去,而要传递超时时间。从而让libev中利用“永远等不到的事件”相关的监视器有机会执行。

利用等待超时这个思路非常有意思。但是又面临另一个问题,超时时间的选择?比如我们现在有两个定时器:2秒一次和3秒一次,那么超时时间该设置成多少呢?如果设置成2秒超时,那么3秒一次的定时器将被延期1秒执行(需要等待到第二个周期)。如果设置为3秒超时,2秒一次的定时器也将被延期1秒执行。如果设置成1秒超时,则超时导致循环的次数增多……这种固定超时的方案怎么都不太好。那么libev是如何解决这个问题的呢?

libev在实现的内部不会有“定时”这样的概念,也就是说每次事件等待的时长是不确定的。这也是为什么各个IO模型需要暴露backend_poll方法的原因——需要每次指定超时的时间。

那这个超时时间怎么计算?每个需要使用等待超时功能触发的监视器,都会在一个结构中保存下次触发的时间。以上面例子为例,并且假设没有其他事件的干扰,假如现在时间是12:00:00,则2秒一次定时器监视器(后称2秒监视器)的“下次执行时间”为12:00:02;3秒一次的定时器监视器(后称3秒监视器)的“下次执行时间”为12:00:03。那么本次等待的时间是离当前时间最近的2秒监视器“下次执行时间”减去当前时间,即12:00:02-12:00:00=2秒。等到时间为12:00:02时,2秒定时器会被执行,并且其“下次执行时间”修改成12:00:04。假设2秒定时器和本次循环中逻辑的执行时间消耗了0.5秒,此时时钟已经走到12:00:02.5。此时离现在最近的“下次执行时间”是3秒监视器,则下次循环的等待时间是12:00:03-12:00:02.5=0.5秒。于是12:00:03时,3秒监视器会被执行。

上面例子解释了libev超时时间选择的基本原理。当然实际实现比这个稍微复杂一点,因为它要考虑相对时间定时器、绝对时间定时器、其他一些用户设置的事件以及各种IO模型的默认等待时间。

/* calculate blocking time */{ev_tstamp waittime  = 0.;ev_tstamp sleeptime = 0.;/* remember old timestamp for io_blocktime calculation */ev_tstamp prev_mn_now = mn_now;/* update time to cancel out callback processing overhead */time_update (EV_A_ 1e100);/* from now on, we want a pipe-wake-up */pipe_write_wanted = 1;ECB_MEMORY_FENCE; /* make sure pipe_write_wanted is visible before we check for potential skips */if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt || pipe_write_skipped))){waittime = MAX_BLOCKTIME;if (timercnt){ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now;if (waittime > to) waittime = to;}#if EV_PERIODIC_ENABLEif (periodiccnt){ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now;if (waittime > to) waittime = to;}
#endif/* don't let timeouts decrease the waittime below timeout_blocktime */if (expect_false (waittime < timeout_blocktime))waittime = timeout_blocktime;/* at this point, we NEED to wait, so we have to ensure *//* to pass a minimum nonzero value to the backend */if (expect_false (waittime < backend_mintime))waittime = backend_mintime;/* extra check because io_blocktime is commonly 0 */if (expect_false (io_blocktime)){sleeptime = io_blocktime - (mn_now - prev_mn_now);if (sleeptime > waittime - backend_mintime)sleeptime = waittime - backend_mintime;if (expect_true (sleeptime > 0.)){ev_sleep (sleeptime);waittime -= sleeptime;}}}#if EV_FEATURE_API++loop_count;
#endifassert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */backend_poll (EV_A_ waittime);

基于上面的分析,对于问题2:“符合条件的监视器”是否可以表述为“本次触发事件对应的监视器”?答案依然是否定的。因为定时器监视器对应的事件永远也不会被等待到,而它被执行只是因为时间到了。

相关文章:

AI颠覆经济世界作用被夸大?影响远比媒体头条报道更加复杂

来源 | The Gradient译者 | 刘畅编辑 | 夕颜出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09; 【导读】每天我们都听到有人声称人工智能将改变经济体系&#xff0c;造成大量的失业和垄断。但是&#xff0c;经济学家是如何看待的呢&#xff1f;在第三届AI经…

ArcGIS制图之Sub Points点抽稀

简介 Sub Points工具是 Esri 中国自主开发的一个插件&#xff0c;该工具优先考虑点在空间分布上的均匀合理性&#xff0c;并结合点数据中包含的 "优先级" 属性进行筛选。通过获取每个点在一定范围内拥有的相邻点的数目信息&#xff0c;得到地图中点密度的分布状况。抽…

libev源码解析——定时器监视器和组织形式

我们先看下定时器监视器的数据结构。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; /* invoked after a specific time, repeatable (based on monotonic clock) */ /* revent EV_TIMEOUT */ typedef struct ev_timer {EV_WATCHER_TIME (ev_timer)ev_tstamp…

谁说AI无用?疫情下,AI已经代替人类做了很多...

整理 | 夕颜出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;经历过无比漫长的十多天&#xff0c;疫情至今还没有任何退散的迹象&#xff0c;形势越来越严峻。百度实时大数据报告显示&#xff0c;截至2020年2月4日9时&#xff0c;新型冠状病毒累计报告确诊病例20471例…

关于CSS样式浏览器兼容问题的一些注意事项

CSS技巧1.div的垂直居中问题 vertical-align:middle; 将行距增加到和整个DIV一样高 line-height:200px; 然后插入文字&#xff0c;就垂直居中了。缺点是要控制内容不要换行 2. margin加倍的问题 设置为float的div在ie下设置的margin会加倍。这是一个ie6都存在的bug。解决…

Ember.js 入门指南——查询记录

2019独角兽企业重金招聘Python工程师标准>>> store提供了统一的获取数据的接口。包括创建新记录、修改记录、删除记录等&#xff0c;更多有关Store API请看这个网址的介绍&#xff1a;http://devdocs.io/ember/data/classes/ds.store。 为了演示这些方法的使用我们结…

C# 视频监控系列(9):服务器端——数据捕获(抓图 + 录像)

前言 录像功能是监控系统中最重要的功能之一&#xff0c;除了本文的功能实现外&#xff0c;还需要你自己考虑合适的存储策略&#xff1a;存储大小、时间段、存储盘符等。 注意 本系列文章限于学习交流&#xff0c;注重过程&#xff0c;由于涉及公司&#xff0c;所以不提供源代码…

疫情当下,你是在家里躺着刷抖音?还是在做这些?

2020年本来可以是很开心的一年没想到一开头就给了我们一个重重的一击疫情的出现让我们非常的恐慌新型病毒肺炎让我们无处可躲原来热闹的新年因为疫情让我们逼不得已只能待在家里走亲访友更是不可能的就连原来约好的相亲也泡汤了因为封城、封村、封小区、封路了而这些也只是为了…

代码打补丁的利器——diff和patch

一般来说&#xff0c;如果我们在研发过程中需要对代码进行修改&#xff0c;是不需要通过打补丁的方式的&#xff0c;因为我们可以直接改动文件即可。但是如果针对一款要上线的产品&#xff0c;我们总不能在研发的电脑上编译通过后直接发布到线上的。&#xff08;转载请指明出于…

React Namespaced Components

2019独角兽企业重金招聘Python工程师标准>>> var MyForm React.createClass({...}); var MyForm.Row React.createClass({...}); var MyForm.Label React.createClass({...}); var MyForm.Input React.createClass({...}); This feature is available in v0.11 …

Linux下HOOK动态链接库中API的方法

2012年&#xff0c;我写了一篇介绍Windows系统下Ring3层API的hook方案——《一种注册表沙箱的思路、实现——Hook Nt函数》&#xff0c;其在底层使用了微软的Detours库。5年后&#xff0c;我又遇到这么一个问题&#xff0c;但是系统变成了Linux。我最开始的想法是找一个Linux下…

NAT的配置与相关概念的理解

试验背景&#xff1a;随着接入因特网的计算机数量不断猛增&#xff0c;IPv4版本地址资源也就愈加显得捉襟见肘。好多企业申请的IP地址都是经过子网不断划分得到的。A类&#xff0c;B类地址基本已用完&#xff0c;而一般的用户根本就申请不到整段的公网C类地址。如果&#xff0c…

AAAI 2020论文解读:商汤科技发布新视频语义分割和光流联合学习算法

来源 | Every Frame Counts: Joint Learning of Video Segmentation and Optical Flow编辑 | Carol出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09; 商汤科技研究团队发表论文《Every Frame Counts: Joint Learning of VideoSegmentation and Optical Flo…

互联网+和创业潮,互联网+前提条件是什么?互联网+做什么?

在大众创业&#xff0c;万众创新的大浪下&#xff0c;凭着对新技术的敏感和青春激情&#xff0c;创业新军不断涌现.... 互联网创业浪潮, 如雨后春笋......,互联网渗透每个人的心中。创业不是赶时髦&#xff0c;而是一条非常孤独&#xff0c;艰难的路。实施“互联网&#xff0b;…

C++拾趣——C++11的语法糖auto

C是一种强类型的语言&#xff0c;比如变量a&#xff0c;如果声明它是整型&#xff0c;则之后只能将它作为整型来用。这和其他弱类型的语言有很大的区别&#xff0c;比如python中&#xff0c;我们可以让a在第一行是个整型&#xff0c;第三行是一个字符串。&#xff08;转载请指明…

“数学不行,啥都干不好!”骨灰级程序员:这比努力重要1000倍

之前有很多程序员读者向我们抱怨&#xff1a;1&#xff09;做算法优化时&#xff0c;只能现搬书里的算法&#xff0c;遇到不一样的问题&#xff0c;就不会了。2&#xff09;面试一旦涉及到算法和数据结构&#xff0c;如果数学不行&#xff0c;面试基本就凉凉了。3&#xff09;一…

跳槽 你准备好了吗

“人往高处走”&#xff0c;这固然没有错。但是&#xff0c;说来轻巧的一句话&#xff0c;它却包含了为什么“走”、什么是“高”、怎么“走”、什么时候“走”&#xff0c;以及“走”了以后怎么办等一系列问题。跳槽是一门学问&#xff0c;也是一种策略。“人往高处走”&#…

C++:常类型Const

常类型&#xff1a;使用类型修饰符const说明的类型&#xff0c;常类型的变量或对象成员的值在程序运行期间是不可改变的。 3.10.1 常引用 如果在说明引用时用const修饰&#xff0c;则被说明的引用为常引用。如果用常引用做形参&#xff0c;便不会产生对实参 的不希望的更改。常…

JQuery制作的toolTip,针对图片预览效果

昨天做了一个文字版的toolTip&#xff0c;后来想想现在大家都爱看图&#xff0c;文字未免有点单调了点&#xff0c;那我们就来个图片式的预览。代码比较简单&#xff0c;我就不多说了。 欢迎来到 买礼网 选购礼品&#xff01; 畅游鄂西山水风光尽在 恩施旅游资讯网首先看看调用…

29篇计算机视觉领域论文,篇篇惊艳!内附链接!

作者 | 微软亚洲研究院本文经授权转载自微软研究院AI头条&#xff08;ID&#xff1a;MSRAsia&#xff09;1. Deep High-Resolution Representation Learning for Human Pose Estimation论文链接&#xff1a;https://arxiv.org/pdf/1902.09212.pdf该论文在提出了一个新的网络Hig…

绑定CPU逻辑核心的利器——taskset

在工作中&#xff0c;我们可能遇到这样的需求&#xff1a;如何评估程序在一核和多核下的工作效率差距&#xff1f;最简单的想法是找一台只有一个CPU逻辑核的机器和一台有多个逻辑核的机器。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09;但是这种方式有明显的…

IDE set arguments

2019独角兽企业重金招聘Python工程师标准>>> code::blocks -> Project -->set programs arguments qtcreater -> Projects --> Build&Run --> Run --> Arguments xcode -> super < -->build-->arguments 转载于:https://my.osch…

2020年AI如何走?Jeff Dean和其他四位“大神”已做预测!

作者 | Khari Johnson译者 | 王艳妮 责编 | 胡巍巍出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;人工智能已经不再是随时准备改变世界的状态&#xff0c;而是已经在改变世界。在迈入2020年这新的一年、以及新的20年代之际&#xff0c;笔者请到了AI方面最…

zookeeper快速入门——简介

在几十年前&#xff0c;一个独立的计算机上往往部署着一套完整的应用系统。当时因为网络稳定性及速度的限制&#xff0c;将相关联的服务部署在一台机器上&#xff0c;让它们使用系统机制通信——比如管道&#xff0c;文件等&#xff0c;往往是最稳定和最高效的。然而随着网络技…

为TextMate扩展全屏功能

今天看代码&#xff0c;感觉TextMate那个窗口太小了点&#xff0c;越看越不爽&#xff0c;就想把它弄成全屏的。于是搜索啊搜索啊搜索&#xff0c;终于让我找到一款很yd的小软件&#xff0c;叫megazoomer&#xff0c; 下载地址是&#xff1a;[url]http://ianhenderson.org/mega…

hdu1406

一道很水很水的题&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;#include<iostream> using namespace std; int main(){int num1,num2,i,k,j,sum,n;while(cin>>n){ while(n--){cin&g…

zookeeper快速入门——部署

zookeeper有两种运行模式&#xff1a;独立模式和仲裁模式。独立模式就是只运行一个Zookeeper Server&#xff0c;这自然没法解决服务崩溃导致系统不可用的问题。仲裁模式就是以集群的方式运行Zookeeper Server&#xff0c;这样在Leader不可用时&#xff0c;集群内部会发起选举&…

2020,人工智能和深度学习未来的五大趋势

来源 | forbes编译 | Shawn编辑 | Carol出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;虽然近年来人工智能经常成为热门议题&#xff0c;但它还远未实现真正的成就。人工智能技术发展的主要障碍在于投资成本&#xff0c;投资成本影响短期内的回报。而当时…

电脑常见故障 1

死机恐怕是所有电脑故障里面最常见的一种了&#xff0c;但是死机的原因是多种多样的。 如果从硬件入手&#xff0c;先是看看机箱里的温度是否很高&#xff0c;要检查CPU的风扇是否正常运转&#xff0c;并要注意电脑的散热问题&#xff1b;其次可检查内存&#xff0c;检查完内存…

linux常用命令-date-clock-hwclock-type-whois--help-man-info-cal

date&#xff1a;时间管理电子表&#xff1a;晶体震荡器 石英震荡器Linux&#xff1a;rtc 硬件时间NTP&#xff1a;网络时间协义硬件时间&#xff08;命令&#xff1a;clock&#xff09;系统时间&#xff08;命令&#xff1a;date&#xff09;type COMMAND 判断命令是内部命令…