技术笔记:libev学习(一)

简介: 技术笔记:libev学习(一)

一.libev简介


  Libev是一个事件循环:你注册感兴趣的特定事件(比如一个文件可以读取时或者发生超时时),它将管理这些事件源,将这些事件反馈给你的程序。为了实现这些,至少要在你的进程(或线程)中执行事件循环句柄控制,然后就能通过回调机制进行事件通信。你通过所谓的watchers注册感兴趣的特定事件,这些watchers都是相对较小的C语言结构体,它们通过初始化具体的事件得到,然后交由libev启动那个watcher。


Libev支持 //代码效果参考:http://www.jhylw.com.cn/012622159.html

select,poll,Linux特有的epoll,BSD特有的kqueue以及Solaris特有的文件描述符事件端口机制(ev_io),Linux信息通知接口(ev_stat),Linux事件文件/信号文件(为了更快更完整的唤醒沉睡线程(ev_async)/信号捕捉(ev_signal))相对定时器(ev_timer),用户自定义的绝对定时器(ev_periodic),同步信号(ev_signal),进程状态改变事件(ev_child),和通过事件循环机制实现的事件观察者管理本身(ev_idle,ev_embed,ev_prepare和ev_check监控)也和文件监控(ev_stat)和有限支持的派生子进程事件(ev_fork)一样。

二.libev特点


  1.关于时间:时间类型为ev_tstamp (Libev描述时间采用一个浮点数,它来自于距离(POSIX)时期的一个(带小数)的秒数)。


  2.错误处理:Libev 知道三类错误:操作系统错误、用法错误和内部错误(bugs) 


当 libev 捕捉到无法处理的操作系统错误时(如一个系统调用返回了libev不能识别的返回值),它通过调用 ev_set_syserr_cb设定的回调函数,它假设这个回调函数可修正这个问题或者是退出。默认行为是打印一个摘要信息并调用 abort()。


当 libev 检测到用法错误(如负的时间),它会打印一条摘要信息并退出(使用 assert 机制,因此宏 NDEBUG 会关闭这种检测); 表明这里有libev调用端的编程错误需要修正。


Libev也有一些内部错误检查,也有大多数的代码错误检查。这些在正常情况下不会触发,他们表明在libev存在一个bug或者更大的错误。


3.全局函数(这些函数可以在任何时候被调用,甚至可以在初始化libev库之前调用)


ev_tstamp ev_time () //返回libev使用它时的当前时间。请注意,ev_now函数通常更快,也经常用来返回你想知道的时间戳。ev_now_update和ev_now组合在一起使用更好


ev_sleep (ev_tstamp interval) //休眠指定的时间间隔:当前线程将被阻塞直到它被中断或者给定的时间间隔已经过去。当interval <= 0.时将立即返回.基本上这是一个精度稍低的sleep()函数.Interval的值是有限制的-libev只保证休眠时间最长为一天(interval <= 86400


int ev_version_major ()


int ev_version_minor () //通过调用ev_version_major 和ev_version_minor函数,你可以找出主要的和次要的ABI链接库版本号。如果需要,你可以比较全局字段EV_VERSION_MAJOR 和 EV_VERSION_MINOR,它们表明了你的程序编译完成后的库版本。


  ev_set_allocator (void (cb)(void ptr, long size)) //这是申请或释放内存的,如果申请内存是返回0,当内存需要被分配(大小!= 0),库可能中止或采取一些潜在的破坏性的行动


例:


static void


persistent_realloc (void ptr, size_t size)


{


for (;;)


{


void newptr = realloc (ptr, size);


if (newptr)


return newptr;


sleep (60);


}


}


...


ev_set_allocator (persistent_realloc);


View Code


ev_set_syserr_cb (void (cb)(const char msg)) //设置发生回系统错误时的调函数


  例:    


static void


fatal_error (const char msg)


{


perror (msg);


abort ();


}


...


ev_set_syserr_cb (fatal_error);


View Code


  ev_feed_signal (int signum) //这个函数可以用来“模拟”一个信号接收。它是完全安全的调用这个函数在任何时间,从任何上下文,包括信号处理程序或随机线程。


  4.该库知道两种类型的循环,默认的循环(支持子进程事件)和动态创建事件循环


struct ev_loop ev_default_loop (unsigned int flags)


常用:ev_default_loop (EVBACKEND_POLL | EVBACKEND_SELECT | EVFLAG_NOENV); //限制测试程序的select、poll的后端,不允许环境设置要考虑


struct ev_loop ev_loop_new (unsigned int flags) //这个函数是线程安全的,常用方式:使用ev_loop_new创建一个时间循环在每个线程中,在主线程中使用默认事件循环。 The flags argumentis usually specified as 0 (or EVFLAG_AUTO).


flags argumentis:


EVFLAG_AUTO:默认值,常用


EVFLAG_NOENV:指定 libev 不使用LIBEV_FLAGS环境变量。常用于调试和测试


EVFLAG_FORKCHECK:与ev_loop_fork()相关,本文暂略


EVFLAG_NOINOTIFY:在ev_stat监听中不使用inotify API


EVFLAG_SIGNALFD:在ev_signal监听中使用signalfd API


EVFLAG_NOSIGMASK:使 libev 避免修改 signal mask。这样的话,你要使 signal 是非阻塞的。在未来的 libev 中,这个 mask 将会是默认值。


EVBACKEND_SELECT:通用后端


EVBACKEND_POLL:除了 Windows 之外的所有后端都可以用


EVBACKEND_EPOLL:Linux 后端


EVBACKEND_KQUEUE:大多数 BSD 的后端


EVBACKEND_DEVPOLL:Solaris 8 后端


EVBACKEND_PORT:Solaris 10 后端


ev_loop_destroy (loop) //Destroys an event loop object


   ev_loop_fork (loop)


int ev_is_default_loop (loop) //判断是否是默认事件循环,是返回ture


unsigned int ev_iteration (loop) //返回当前的 loop 的迭代数。等于 libev pool 新事件的数量(?)。这个值对应ev_prepare和ev_check调用,并在 prepare 和 check 之间增一


unsigned int ev_depth (loop) //返回ev_run()进入减去退出次数的差值


unsigned int ev_backend (struct ev_loop loop);


返回EVBACKEND_


ev_tstamp ev_now (loop)


得到当前的“event loop time”。在 callback 调用期间,这个值是不变的。


void ev_new_update (loop)


更新从ev_now()中返回的时间。不必要的话,不要使用,因为这个函数的开销相对是比较大的。


void ev_suspend (struct ev_loop loop);


void ev_resume (struct ev_loop loop);


暂停当前的 loop,使其刮起当前的所有工作。同时其 timeout 也会暂停。如果恢复后,timer 会从上一次暂停状态继续及时——这一点对于实现一些要连同时间也一起冻结的功能时,非常有用。


注意已经 resume 的loop不能再 resume,反之已经 suspend 的 loop 不能再 suspend。


bool ev_run (struct ev_loop loop, int flags);


初始化 loop 结束后,调用这个函数开始 loop。如果 flags == 0,直至 loop 没有活跃的时间或者是调用了 ev_bread 之后停止。


Loop 可以是异常使能的,你可以在 callback 中调用longjmp来终端回调并且跳出 ev_run,或者通过抛出 C++ 异常。这些不会导致 ev_depth 值减少。


EVRUN_NOWAIT会检查并且执行所有未解决的 events,但如果没有就绪的时间,ev_run 会立刻返回。EVRUN_ONCE会检查所有的 events,在至少每一个 event 都执行了一次事件迭代之后才返回。但有时候,使用ev_prepare/ev_check更好。


以下是ev_run的大致工作流程:


loop depth ++


重设ev_break状态


在首次迭代之前,调用所有 pending watchers


LOOP:


如果置了EVFLAG_FORKCHECK,则检查 fork,如果检测到 fork,则排队并调用所有的 fork watchers


排队并且调用所有 ready 的watchers


如果ev_break被调用了,则直接跳转至 FINISH


如果检测到了 fork,则分离并且重建 kernel state


使用所有未解决的变化更新 kernel state


更新ev_now的值


计算要 sleep 或 block 多久


如果指定了的话,sleep


loop iteration ++


阻塞以等待事件


排队所有未处理的I/O事件


更新ev_now的值,执行 time jump 调整


排队所有超时事件


排队所有定期事件


排队所有优先级高于 pending 事件的 idle watchers


排队所有 check watchers


按照上述顺序的逆序,调用 watchers (check watchers -> idle watchers -> 定期事件 -> 计时器超时事件 -> fd事件)。信号和 child watchers 视为 fd watchers。


如果ev_break被调用了,或者使用了EVRUN_ONCE或者EVRUN_NOWAIT,则如果没有活跃的 watchers,则 FINISH,否则 continue


FINISH:


如果是EVBREAK_ONE,则重设 ev_break 状态


loop depth --


return


void ev_break (struct ev_loop loop, how);


中断 loop。参数可以是 EVBREAK_ONE(执行完一个内部调用后返回)或EVBREAK_ALL(执行完所有)。


下一次调用 ev_run 的时候,相应的标志会清除


void ev_ref (struct //代码效果参考:http://www.jhylw.com.cn/505726521.html

ev_loop loop);

void ev_unref (struct ev_loop loop);


类似于 Objective-C 中的引用计数,只要 reference count 不为0,ev_run 函数就不会返回。


在做 start 之后要 unref;stop 之前要 ref。


void ev_set_io_collect_interval (struct ev_loop loop, ev_tstamp interval);


void ev_set_timeout_coll

相关文章
|
网络协议 安全
libev与多线程
libev与多线程
libev与多线程
|
9月前
|
人工智能 IDE 程序员
凌晨三点,你的眼睛还撑得住吗?——聊聊程序员「夜战」的真实成本!
当代程序员每日盯屏超10小时,眼睛疲劳、注意力分散成常态。本文从真实体验出发,探讨如何通过“为程序员定制”的显示器(如明基RD280U),以3:2画幅、编程色彩模式、MoonHalo护眼背光、KVM多设备协同等设计,系统性缓解暗光刺眼、蓝光伤眼、频繁切换等痛点,让屏幕真正服务于专注与健康——因为代码可重构,眼睛不能。
568 1
凌晨三点,你的眼睛还撑得住吗?——聊聊程序员「夜战」的真实成本!
|
4月前
|
机器学习/深度学习 人工智能 安全
零基础保姆级指南!OpenClaw(Clawdbot)阿里云/本地秒级部署接入大模型DeepSeek V3.2教程
2026年,开源AI智能体工具迎来爆发式迭代,OpenClaw(曾用名Clawdbot、MoltBot)凭借轻量化架构、多平台适配、插件化扩展及原生多模型兼容特性,成为个人与轻量团队实现自动化办公、开发辅助、长文本处理的核心工具。其核心优势在于可将自然语言指令转化为实际系统操作,打破传统AI“只说不做”的局限,而DeepSeek V3.2作为2026年开源大模型领域的标杆产品,通过DeepSeek稀疏注意力(DSA)机制、可扩展强化学习框架等核心技术突破,在长上下文处理、复杂推理、工具调用等方面实现跨越式提升,甚至在多项权威基准测试中追平闭源巨头,两者协同可充分释放AI智能体的核心价值。
2642 13
|
安全 Linux 开发工具
【Linux】vim使用与配置教程
Vim是一款功能强大的文本编辑器,广泛应用于Linux环境,是开发者和系统管理员的必备工具。本文介绍了Vim的基本操作与简单配置,涵盖命令模式、插入模式和底行模式的使用方法,以及光标定位、复制粘贴、搜索替换等常用技巧。同时,文章还提供了实用的分屏操作和代码注释方法,并分享了通过`.vimrc`文件进行个性化配置(如显示行号、语法高亮、自动缩进等)的技巧,帮助用户提升文本编辑效率。掌握这些内容,能让Vim更好地服务于日常工作与开发需求。
1151 3
|
12月前
|
人工智能 Linux Go
window 部署 coze-loop
本教程介绍了如何在 Linux 系统上安装 Go 环境、Docker 以及 Coze Loop,并配置多模型运行。内容包括安装步骤、环境变量设置、代码拉取、模型配置及服务启动等关键流程,适用于搭建本地化的 AI 模型服务环境。
1202 7
window 部署 coze-loop
|
物联网
云服务器搭建rttys服务
RTTYS是一款基于Web的串口调试工具,分为服务端(rttys)和客户端(rtty)。服务端负责连接串口设备并提供接口,客户端通过浏览器访问实现远程串口调试。它具有跨平台、易部署的特点,适用于物联网、嵌入式开发等场景,极大提升调试效率。
|
机器学习/深度学习 数据采集 数据可视化
基于爬虫和机器学习的招聘数据分析与可视化系统,python django框架,前端bootstrap,机器学习有八种带有可视化大屏和后台
本文介绍了一个基于Python Django框架和Bootstrap前端技术,集成了机器学习算法和数据可视化的招聘数据分析与可视化系统,该系统通过爬虫技术获取职位信息,并使用多种机器学习模型进行薪资预测、职位匹配和趋势分析,提供了一个直观的可视化大屏和后台管理系统,以优化招聘策略并提升决策质量。
1244 4
|
运维 监控 Kubernetes
微服务:监控体系,容器监控
微服务:监控体系,容器监控
微服务:监控体系,容器监控
|
网络协议 安全 Linux
Linux的netns使用总结
Linux的netns(Network Namespace)是一项强大的网络隔离功能,可在内核层面创建多个独立的网络空间,每个空间配备独立的网络协议栈,包括接口、路由表及iptables规则等,确保不同应用或服务在网络环境中互不干扰,提升系统安全性和灵活性。通过`ip netns`命令可轻松管理netns,实现创建、删除及执行命令等功能。netns适用于容器技术、虚拟化环境及网络测试等多种场景,为用户提供高效、安全的网络环境管理方案。
1591 3
|
消息中间件 安全 Java
ulimit 命令详解
ulimit 命令详解
1276 0