libuv事件循環中的三種句柄


1、說明

本文會簡單介紹 libuv 的事件循環,旨在入門級別的使用,而不做深入探究,簡單來說就是,會大概用就行,先用熟練了,再去探究原理和源碼

下圖為官網的 libuv 的不同部分及其涉及的子系統的圖:

img

libuv 使用 handlesrequests 來結合使用事件循環

handles 表示能夠執行某些耗時的長時間存在的對象

requests 表示短暫的操作,可以在一個 handles 上執行

下圖為官網的事件循環:

_images / loop_iteration.png

這張圖其實表明了 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 相關的代碼,主要用於熟悉三種句柄回調函數的執行順序


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM