1、说明

本文会简单介绍 libuv 的事件循环,旨在入门级别的使用,而不做深入探究,简单来说就是,会大概用就行,先用熟练了,再去探究原理和源码

下图为官网的 libuv 的不同部分及其涉及的子系统的图:

libuv 使用 handlesrequests 来结合使用事件循环

handles 表示能够执行某些耗时的长时间存在的对象

requests 表示短暂的操作,可以在一个 handles 上执行

下图为官网的事件循环:

这张图其实表明了 libuv 中的时间循环的处理过程,也就是 uv_run() 方法执行的过程,该方法内部是一个 while 循环:

  1. 先判断循环是都处于活动状态,通过判断当前是否处于 alive 状态,来确定事件循环是否退出;
  2. 运行倒计时定时器(维护所有句柄的定时器);
  3. 执行待执行的回调函数;
  4. 运行 idle 句柄;
  5. 运行 prepare 句柄;
  6. 轮询 I/O;
  7. 运行 check 句柄;
  8. 调用 close 回调;

上述步骤中,有三个句柄被重点标出,我们就来讨论这三个句柄

2、idle句柄

idle handle 即空闲句柄,从上面流程图上可以看出,如果启动了 idle handle,每次事件循环的时候都会执行一遍其回调

2.1、uv_idle_init

该方法用于初始化 idle handle

int uv_idle_init(uv_loop_t* loop, uv_idle_t* idle)

uv_idle_tidle 句柄类型

该方法永远执行成功,返回值0

2.2、uv_idle_start

该方法用于开始 idle handle

int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb)

该方法用于都是执行成功的(返回值0),除非回调函数设置为 NULL(此时返回 UV_EINVAL

回调函数声明如下:

void (*uv_idle_cb)(uv_idle_t* handle);

回调函数会把句柄带过去

2.3、uv_idle_stop

该方法用于停止 idle handle

int uv_idle_stop(uv_idle_t* idle)

该方法永远执行成功,返回值0

执行之后,回调不会再执行

3、prepare句柄

可以理解成准备句柄,从流程图中可以看出,在 idle 之后,在轮询 IO 之前执行其回调

其API和 idle 差不多

3.1、uv_prepare_init

int uv_prepare_init(uv_loop_t* loop, uv_prepare_t* prepare);

初始化句柄,uv_prepare_tprepare 句柄类型

返回值0,总是成功的

3.2、uv_prepare_start

int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb);

开始句柄,执行总是成功的(返回0),除非回调函数为 NULL(此时返回 UV_EINVAL )

void (*uv_prepare_cb)(uv_prepare_t* handle);

3.3、uv_prepare_stop

int uv_prepare_stop(uv_prepare_t* prepare);

停止句柄,回调函数不会再执行

4、check句柄

可以理解为检查句柄,如果程序中启动了 check 句柄,则在每次轮询 IO 之后执行其回调函数,正好和 prepare 前后呼应

这种设计的机制是 libuv 为用户预留的借口,在轮询 IO 循环状态前后进行准备和校验操作

其 API 和上面两种句柄类似

4.1、uv_check_init

int uv_check_init(uv_loop_t* loop, uv_check_t* check);

初始化句柄,uv_check_tcheck 句柄类型

方法执行总是成功的

4.2、uv_check_start

int uv_check_start(uv_check_t* check, uv_check_cb cb);

开始句柄,回调函数可以为 NULL

方法执行总是成功的(返回0),除非回调函数为 NULL(返回UV_EINVAL )

void (*uv_check_cb)(uv_check_t* handle);

4.3、uv_check_stop

int uv_check_stop(uv_check_t* check);

停止句柄,回调函数不会再执行

方法执行总是成功的,返回0

5、代码示例

#include <stdio.h>
#include <stdlib.h>
#include <uv.h> #define MAX_NUM 3 int count = 0;
void idle_cb(uv_idle_t *handle)
{
count++;
printf("idle handle callback, count = %d\n", count);
if (count >= MAX_NUM)
{
printf("idle handle stop, count = %d\n", count);
uv_stop(uv_default_loop());
}
} void prepare_cb(uv_prepare_t *handle)
{
printf("prepare handle callback\n");
} void check_cb(uv_check_t *check)
{
printf("check handle callback\n");
} int main()
{
uv_idle_t idle;
uv_prepare_t prepare;
uv_check_t check; uv_idle_init(uv_default_loop(), &idle);
uv_idle_start(&idle, idle_cb); uv_prepare_init(uv_default_loop(), &prepare);
uv_prepare_start(&prepare, prepare_cb); uv_check_init(uv_default_loop(), &check);
uv_check_start(&check, check_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); return 0;
}

输出结果如下:

idle handle callback, count = 1
prepare handle callback
check handle callback
idle handle callback, count = 2
prepare handle callback
check handle callback
idle handle callback, count = 3
idle handle stop, count = 3
prepare handle callback
check handle callback

上例子中没有 IO 相关的代码,主要用于熟悉三种句柄回调函数的执行顺序

libuv事件循环中的三种句柄的更多相关文章

  1. libuv事件循环

    目录 1.说明 2.数据类型 2.1.uv_loop_t 2.2.uv_walk_cb 3.API 3.1.uv_loop_init 3.2.uv_loop_configure 3.3.uv_loop ...

  2. Java三大框架之——Hibernate中的三种数据持久状态和缓存机制

    Hibernate中的三种状态   瞬时状态:刚创建的对象还没有被Session持久化.缓存中不存在这个对象的数据并且数据库中没有这个对象对应的数据为瞬时状态这个时候是没有OID. 持久状态:对象经过 ...

  3. iOS容易造成循环引用的三种场景

    iOS容易造成循环引用的三种场景  ARC已经出来很久了,自动释放内存的确很方便,但是并非绝对安全绝对不会产生内存泄露.导致iOS对象无法按预期释放的一个无形杀手是--循环引用.循环引用可以简单理解为 ...

  4. Asp.Net中的三种分页方式

    Asp.Net中的三种分页方式 通常分页有3种方法,分别是asp.net自带的数据显示空间如GridView等自带的分页,第三方分页控件如aspnetpager,存储过程分页等. 第一种:使用Grid ...

  5. 研究分析JS中的三种逻辑语句

    JS中的三种逻辑语句:顺序.分支和循环语句. 一.顺序语句 代码规范如下:1. <script type="text/javascript"> var a = 10;  ...

  6. Netty中的三种Reactor(反应堆)

    目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...

  7. js oop中的三种继承方法

    JS OOP 中的三种继承方法: 很多读者关于js opp的继承比较模糊,本文总结了oop中的三种继承方法,以助于读者进行区分. <继承使用一个子类继承另一个父类,子类可以自动拥有父类的属性和方 ...

  8. SQL Server中的三种Join方式

      1.测试数据准备 参考:Sql Server中的表访问方式Table Scan, Index Scan, Index Seek 这篇博客中的实验数据准备.这两篇博客使用了相同的实验数据. 2.SQ ...

  9. 【转载】C#批量插入数据到Sqlserver中的三种方式

    引用:https://m.jb51.net/show/99543 这篇文章主要为大家详细介绍了C#批量插入数据到Sqlserver中的三种方式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 本篇, ...

随机推荐

  1. idea中Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' property manually.

    我本机安装的mysql版本是5.7的,那么IDEA要连接mysql也应该匹配下驱动版本.把Driver改成MySQL for 5.1就可以了 在点击Test Connection测试下,成功啦!

  2. Java JVM——8.堆

    堆的核心概念 堆针对一个 JVM 进程来说是唯一的,也就是一个进程只有一个JVM,但是进程包含多个线程,他们是共享同一堆空间的. 一个JVM实例只存在一个堆内存,堆也是Java内存管理的核心区域. J ...

  3. 数据库事务特性ACID

    事务 事务(Transaction),一般是指要做的或所做的事情.在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit).在计算机术语中,事务通常就是指数据库事务. 概念 一 ...

  4. java中网络通信 Scoket

    在客户/服务器通信模式中,客户端需要主动建立与服务器连接的Socket,服务器端收到客户端的连接请求,也会创建与客户端连接的Socket.Socket可以看做是通信连接两端的收发器,客户端和服务店都通 ...

  5. java 多态 向上造型

    最近在读java 编程思想,在读多态一章时,遇到了一个问题,在此记录一下. 1 package main.demo; 2 3 class Super{ 4 public int filed =0; 5 ...

  6. Cocos Creator 新资源管理系统剖析

    目录 1.资源与构建 1.1 creator资源文件基础 1.2 资源构建 1.2.1 图片.图集.自动图集 1.2.2 Prefab与场景 1.2.3 资源文件合并规则 2. 理解与使用 Asset ...

  7. Java 双端队列接口 Deque

    Deque 是一种支持在两端进行操作的线性结构,包含了栈和队列的功能.Java 中建议使用 Dqueue 的实现来替代遗留的 Stack 类.本文将介绍 Deque 提供的主要 API. 双端操作 A ...

  8. 【JavaWeb】Servlet 程序

    Servlet 程序 Servlet Servlet 是在 Web 服务器中运行的小型 Java 程序.Servlet 通常通过 HTTP(超文本传输​​协议)接收和响应来自 Web 客户端的请求. ...

  9. Java基础进阶类名整理

    类名综合 数学类: Math:数学运算 BigDecimal:用于精确计算数据 数组工具类: Arrays:数组工具类,用于对数组的操作 时间操作: JDK8以前: Date:表示一个时间,并面向对象 ...

  10. python面向对象基础-属性/方法