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. IaaS、PaaS、SaaS、DaaS都是什么?现在怎么样了?终于有人讲明白了

    导读:本文将详细科普云计算的概念.云服务的发展现状,并逐一介绍各种云服务模式(IaaS.PaaS.SaaS.DaaS),建议收藏! 作者:阿里云智能-全球技术服务部来源:大数据DT(ID:bigdat ...

  2. Tomcat服务器的下载以及配置

    1,Tomcat的下载与安装 本人采用的是解压版安装,只需要在官网(https://tomcat.apache.org/)下载好压缩版的Tomcat,再解压在你想安装的目录下即可.我的安装目录是D:\ ...

  3. Maven仓库是什么

    Maven仓库是基于简单文件系统存储的,集中化管理Java API资源(构件)的一个服务.仓库中的任何一个构件都有其唯一的坐标,根据这个坐标可以定义其在仓库中的唯一存储路径.得益于 Maven 的坐标 ...

  4. javaweb登陆实例

    1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncod ...

  5. request常用方法servlet初步

    1 package com.ycw.newservlet; 2 3 import java.io.IOException; 4 import javax.servlet.ServletExceptio ...

  6. Fragment学习

    利用Fragment可以动态的加载页面,减少Activity的数量. 便于开发 类似与html中FragmentSet一样 嵌套在一起,使每个页面为独立的 代码如下: package com.exam ...

  7. 配置NFS实现nginx动静分离

    案例子任务一.安装配置NFS服务器 步骤1:使用docker容器配置NFS服务器 启动centos容器并进入 docker run -d --privileged centos:v1 /usr/sbi ...

  8. UDP 通讯方式

    1.创建套接字:2.绑定端口:3.收发数据: 收到的数据中包含发送方的端口信息4.关闭套接字:

  9. Golang字符串是否存在于切片或数组中的小工具(基本等同于python in语法)

    // golang中是没有判断字符串是否存在数组或切片里的内置方法, 所以我们可以自己搞一个快速小组件 func Find(slice []string, val string) (int, bool ...

  10. flask socketio 踩坑记录

    在使用python3的flask-socketio+socket.io.js的时候报错 在使用python3的flask-socketio+socket.io.js的时候报错"unsuppo ...