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. 发送微信通知 java

    //实现类@Service public class WeChatServiceImpl implements IWeChatService { @Override public WeChatSend ...

  2. [leetcode712]204. Count Primes寻找范围内的素数

    厄拉多塞筛选法,就是哈希表记录素数的倍数 public int countPrimes(int n) { /* 牛逼哄哄的厄拉多塞筛选法 就是从2开始,每找到一个素数,就把n以内的这个数的倍数排除 记 ...

  3. [Machine Learning] 逻辑回归 (Logistic Regression) -分类问题-逻辑回归-正则化

    在之前的问题讨论中,研究的都是连续值,即y的输出是一个连续的值.但是在分类问题中,要预测的值是离散的值,就是预测的结果是否属于某一个类.例如:判断一封电子邮件是否是垃圾邮件:判断一次金融交易是否是欺诈 ...

  4. 人脸识别--SeetaFace

    检测:http://download.csdn.net/detail/qq_14845119/9639840 对齐:http://download.csdn.net/detail/qq_1484511 ...

  5. mysql组合索引之最左原则

    为什么在单列索引的基础上还需要组合索引? select product_id from orders where order_id in (123, 312, 223, 132, 224); 我们当然 ...

  6. 基于websocket的netty demo

    前面2文 基于http的netty demo 基于socket的netty demo 讲了netty在http和socket的使用,下面讲讲netty如何使用websocket websocket是h ...

  7. 用隧道协议实现不同dubbo集群间的透明通信

    用隧道协议实现不同dubbo集群间的透明通信 前言 笔者最近完成了一个非常有意思的隧道机制(已在产线运行),可以让注册到不同zookeeper之间的dubbo集群之间能够正常进行通信.如下图所示: 例 ...

  8. 通过实例学习 PyTorch

    通过范例学习 PyTorch 本博文通过几个独立的例子介绍了 PyTorch 的基础概念. 其核心,PyTorch 提供了两个主要的特征: 一个 n-维张量(n-dimensional Tensor) ...

  9. CopyOnWriteArrayList设计思路与源码分析

    CopyOnWriteArrayList实现了List接口,RandomAccess,Cloneable,Serializable接口. CopyOnWriteArrayList特性 1.线程安全,在 ...

  10. leetcode-222完全二叉树的节点个数

    题目 给出一个完全二叉树,求出该树的节点个数. 说明: 完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置. ...