libev的ev_periodic介绍
Periodic监视器也是libev中定时器的一种,其功能很多,但实现较为复杂。与ev_timer不同,periodic监视器不是基于实时(或相对时间,即过去的物理时间),而是基于钟表时间(绝对时间,及系统钟表过去的事件)。不同的是,钟表时间可能比实时时间跑得快或慢,时间跳跃并不罕见(例如,当你调整钟表时间),通常更适合长时间的计时。
可以让periodic监视器在某个特定时间点后触发:例如,如果希望“在10秒内”触发(通过指定例如ev_now () + 10)。也就是说,绝对时间而不是延迟),然后将系统时钟重置为前一年的1月,则需要一年或更长时间来触发事件(不像ev_timer,它在启动后仍会触发大约10秒,因为它使用相对超时)。
periodic监视器也可以用来实现更复杂的计时器,比如在每个“当地时间的午夜”触发一个事件,或者其他复杂的规则。这一点ev_timer watcher很难做到,因为无法对时间跳跃做出反应。
与计时器一样,回调保证只在应该触发的时间点过去时才被调用。如果多个定时器在同一个循环迭代中准备好了,那么具有更早超时值的定时器将在具有更晚超时值的定时器之前被调用(当回调递归调用ev_run时,情况就不同了)
主要函数:
ev_periodic_init (ev_periodic *, callback, ev_tstamp offset, ev_tstamp interval, reschedule_cb)
ev_periodic_set (ev_periodic *, ev_tstamp offset, ev_tstamp interval, reschedule_cb)
很多参数,实际上有三种操作模式,我们直接介绍操作模式,将从最简单到最复杂来解释:
1)绝对时间定时器:absolute timer (offset = absolute time, interval = 0, reschedule_cb = 0)
在这种配置中,检测器在时钟时间offset过去后触发一个事件。当发生时间跳跃时,它不会重复也不会调整,也就是说,如果它在2020年1月1日运行,那么当系统时钟达到或超过该时间点+offset时,它将被停止并调用。
2)重复间隔定时器:repeating interval timer (offset = offset within interval, interval > 0, reschedule_cb = 0)
在这种模式下,监视器将总是被安排在下一个(offset + N * interval
)时间超时(N为整数,它也可以是负的),然后重复,而不管任何时间跳跃,偏移参数仅仅是间隔周期的偏移。可用于创建不随系统时钟漂移的定时器,例如,创建一个每小时触发的ev_periodic:
ev_periodic_set (&periodic, 0., 3600., 0);
这并不意味着两次触发之间总是有3600秒的间隔,而只是当系统时间显示为一个完整小时(UTC)时,或者更准确地说,当系统时间可被3600整除时,才会调用回调。另一种更偏向数学的解释是ev_periodic将在下一个满足time = offset (mod interval)的时间运行回调,而不考虑任何时间跳跃。interval必须是正的,并且为了数值稳定,interval应该大于1/8192(大约100微秒),offset应该大于0,并且最多应该具有与当前时间相似的幅度(比如说,在10倍之内)。offset的典型值实际上是0或介于0和interval之间的值,这也是推荐的范围。还要注意,定时器触发的频率是有上限的(例如,CPU速度),所以如果间隔很小,那么定时稳定性当然会下降。Libev本身试图精确到大约一毫秒(如果操作系统支持并且机器足够快)。
3)手动重安排模式: manual reschedule mode (offset ignored, interval ignored, reschedule_cb = callback)
它必须根据过去的时间值(即大于第二个参数的最低时间值)返回下一次触发的时间。它通常在回调被触发之前被调用,但也可能在其他时间被调用。 注意:这个回调必须总是返回一个大于或等于现在传递值的时间。 这可以用来创建非常复杂的计时器,例如在“下一个午夜,当地时间”触发的计时器。要做到这一点,需要计算从现在起的下一个午夜,并返回时间戳值。下面是一个关于如何做到这一点的例子:
#include <time.h>static ev_tstampmy_rescheduler (ev_periodic *w, ev_tstamp now){time_t tnow = (time_t)now;struct tm tm;localtime_r (&tnow, &tm);tm.tm_sec = tm.tm_min = tm.tm_hour = 0; // midnight current day++tm.tm_mday; // midnight next dayreturn mktime (&tm);}
最后给出一个例子很好的说明三种基本方法的使用:
#include <ev.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h> // for fmod#define TIMEOUT 4.
struct ev_loop *loop = NULL;
ev_periodic periodic_watcher;static void periodic_cb(struct ev_loop *loop, ev_periodic *w, int revents)
{printf("periodic_cb() call\n");
}static ev_tstamp scheduler_cb(ev_periodic *w, ev_tstamp now)
{double mod = fmod(now, TIMEOUT);printf("scheduler_cb() call, now = %lf, mod = %lf\n", now, mod);return now + (TIMEOUT - mod);
}void *ev_periodic_create(void *p)
{loop = ev_loop_new(EVFLAG_AUTO);// 下面三种初始化方法都可以,实现的效果是一样的。//ev_periodic_init(&periodic_watcher, periodic_cb, 0., TIMEOUT, 0); // periodic_cb每隔TIMEOUT秒被调用一次,对应基本方法1.//ev_periodic_init(&periodic_watcher, periodic_cb, fmod(ev_now(loop), TIMEOUT), TIMEOUT, 0); // periodic_cb每隔TIMEOUT秒被调用一次,对应基本方法2.
ev_periodic_init(&periodic_watcher, periodic_cb, 0., 0., scheduler_cb); // periodic_cb每隔TIMEOUT秒被调用一次,对应基本方法3.// 需要注意的是对于第三种初始化方法,执行下面这个方法后会主动去调用一次scheduler_cb函数(但此时并不触发periodic_cb函数),以后就是每隔TIMEOUT秒后才调用scheduler_cb,并且触发periodic_cb。ev_periodic_start(loop, &periodic_watcher);printf("ev_periodic_create() call, after start!\n");ev_run(loop, 0);
}int main()
{pthread_t tid;pthread_create(&tid, NULL, ev_periodic_create, NULL);while(1){static int count = 0;printf("count = %d\n", count++);sleep(1);}return 0;
}
其它函数:
ev_periodic_again (loop, ev_periodic *):
只需停止并重新启动定期观察器。只有当更改了一些参数,或者重新计划回调返回的时间与上次调用的时间不同时(例如,在类似crond的程序中,当crontabs发生更改时),这才是有用的。
ev_tstamp ev_periodic_at (ev_periodic *):
激活时,返回观察者下一次触发的绝对时间。这与ev_periodic_set的offset
参数不同,但实际上甚至在间隔和手动重新调度模式下也能工作。
ev_tstamp offset [read-write]:
重复时,它包含偏移值,否则这就是绝对时间点(偏移值传递给ev_periodic_set,尽管libev可能会修改此值以获得更好的数值稳定性)。 可以随时修改,但更改仅在定期计时器触发或再次调用ev _ periodic _时生效。
ev_tstamp interval [read-write]:
当前间隔值。可以随时修改,但更改仅在定期计时器触发或再次调用ev _ periodic _时生效。
ev_tstamp (*reschedule_cb)(ev_periodic *w, ev_tstamp now) [read-write]:
当前的重新计划回调,如果此功能被关闭,则为0。可以随时更改,但更改仅在定期计时器触发或再次调用ev _ periodic _时生效。
libev的ev_periodic介绍相关推荐
- 偷懒的网络框架libevent、libev框架介绍
libevent.libev框架介绍 前言 概述 libevent 编译安装libevent libevent的封装层次 IO事件检测的封装与api介绍 事件管理器event_base `构建事件管理 ...
- 事件驱动库 libev 使用详解
C/C++Linux服务器开发/后台架构师知识体系 libev 是一个通过 C 语言编写的,高性能的事件循环库,支持多种事件类型,与此类似的事件循环库还有 libevent.libubox 等,在此详 ...
- libev 源码解析
一 libev简介 libev是一个轻量级的事件通知库,具备支持多种事件通知能力,通过对libev的源码的阅读,可以清楚了解事件通知实现内部机制. 二 核心数据结构 在libev中关键的数据结构是, ...
- libev libevent简介
最近开始重构定制公司的网站后台服务器,开始关注libevent 以及livev 相关 ,也欢迎相关的同学一起讨论.这两者采用相同的架构和设计思想,很多原理和代码都可以相互参考和对比理解. 简介 lib ...
- libev源码解析——定时器监视器和组织形式
我们先看下定时器监视器的数据结构.(转载请指明出于breaksoftware的csdn博客) /* invoked after a specific time, repeatable (based o ...
- libev源码解析——I/O模型
在<libev源码解析--总览>一文中,我们介绍过,libev是一个基于事件的循环库.本文将介绍其和事件及循环之间的关系.(转载请指明出于breaksoftware的csdn博客) 目前i ...
- libev源码解析——调度策略
在<libev源码解析--监视器(watcher)结构和组织形式>中介绍过,监视器分为[2,-2]区间5个等级的优先级.等级为2的监视器最高优,然后依次递减.不区分监视器类型和关联的文件描 ...
- libev源码解析——监视器(watcher)结构和组织形式
在<libev源码解析--总览>中,我们介绍了libev的一些重要变量在不同编译参数下的定义位置.由于这些变量在多线程下没有同步问题,所以我们将问题简化,所提到的变量都是线程内部独有的,不 ...
- libev源码分析---整体设计
libev是Marc Lehmann用C写的高性能事件循环库.通过libev,可以灵活地把各种事件组织管理起来,如:时钟.io.信号等.libev在业界内也是广受好评,不少项目都采用它来做底层的事件循 ...
- 几种服务器端IO模型的简单介绍及实现(转载)
作者:阿凡卢 出处:http://www.cnblogs.com/luxiaoxun/ 服务器端几种模型: 1.阻塞式模型(blocking IO) 我们第一次接触到的网络编程都是从 listen() ...
最新文章
- 性能测试中传——lr理论基础(四)
- zabbix环境安装搭建
- fake it till you become it
- OAG – WhoIsWho 同名消歧竞赛发布 | 10万元奖金双赛道
- 「SLAM」三维空间刚体运动名词笔记
- excel mysql实时交换数据_Excel与数据库的数据交互
- QAbstractTableModel中的data()到底执行几遍???
- JAVA高并发工作笔记0001---高并发编程之ConcurrentLinkedDeque
- 保证MQ消费消息的幂等性,真可以用版本号的方式?
- 达梦8初始化参数之BLANK_PAD_MODE
- pythonsze_python学习笔记二 数据类型(基础篇)
- Sniffing and sending packets is not available: winpcap is not installed
- Newline required at end of file but not found
- matlab频率域滤波器,频率域滤波的MATLAB设计与实现_课程设计
- 【R文档】1 isolation.forest/孤立森林算法
- 安利3款可以将pdf转换成word免费软件
- MySql事务4种隔离级别以及悲观锁和乐观锁
- 实战:为图片生成文本摘要
- 本地推送没有报错,但Github内容不更新的原因
- linux ssh 登陆后欢迎界面 banner 设置操作