libuv工作隊列


1、說明

libuv 提供了一個線程池,可用於運行用戶代碼,libuv 中的工作隊列中的任務會在線程池中執行

libuv 中的線程池在內部用於運行所有文件系統操作以及 getaddrinfo()getnameinfo() 請求

libuv 中的線程池的默認數量為4,可以在啟動時修改環境變量 UV_THREADPOOL_SIZE 來修改,最大值為 1024(1.30.0版本之前是128)

libuv 中的線程池是全局的,並在所有事件循環之間共享,當特定的函數利用 uv_queue_work() 方法使用工作隊列時,libuv 會預分配線程池,以較小的內存開銷(128個線程為1MB),來提高線程性能

以下三種類型的操作會在全局線程池中進行:

  1. 文件系統操作;
  2. DNS函數(getaddrinfo 和 getnameinfo);
  3. 使用 uv_queue_work() 調度的用戶代碼;

需要注意的是,即使使用了線程池,libuv 的方法也不是線程安全的

2、API

2.1、uv_queue_work

int uv_queue_work(uv_loop_t* loop, 
                  uv_work_t* req, 
                  uv_work_cb work_cb, 
                  uv_after_work_cb after_work_cb);

添加一個任務到工作隊列中,在主線程中調用

loop: 事件循環

req: 傳入到任務的數據,一般使用 req.data 參數傳遞

work_cb: 執行方法

after_work_cb: 執行方法完成后執行

work_cb 方法會在函數中執行,after_work_cb 方法在創建線程中執行

void (*uv_work_cb)(uv_work_t* req);
void (*uv_after_work_cb)(uv_work_t* req, int status);

如果調用 uv_cancel 方法取消了隊列,則 uv_after_work_cbstatusUV_ECANCELED

2.2、uv_cancel

int uv_cancel(uv_req_t* req);

取消未執行的隊列中的任務,在任務中調用

req 為任務的參數

如果調用此方法取消了任務,則 after_work_cb 回調函數的 status 的值為 UV_ECANCELED

3、代碼示例

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <uv.h>

void print(uv_work_t *req)
{
    sleep(1);
    long num = (long)req->data;
    printf("thread id is: %ld, num is: %d\n", uv_thread_self(), num);
}

void after_print(uv_work_t *req, int status)
{
    printf("after print, req data is %d, status is %d\n", req->data, status);
}

int main()
{
    uv_loop_t *loop = uv_default_loop();
    uv_work_t req[5];

    for (int index = 0; index < 5; index++)
    {
        req[index].data = (void *)(long)index;
        uv_queue_work(loop, &req[index], print, after_print);
        sleep(1);
    }

    return uv_run(loop, UV_RUN_DEFAULT);
}

示例中的代碼,每次執行 print() 方法都是在不同線程中,after_print() 方法和 main() 方法在同一個線程中


免責聲明!

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



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