libuv学习笔记(20)

libuv学习笔记(20)

线程池工作调度

相关数据结构

typedef struct uv_work_s uv_work_t;

struct uv_work_s {
  UV_REQ_FIELDS//uv_req_t的成员
  uv_loop_t* loop;
  uv_work_cb work_cb;
  uv_after_work_cb after_work_cb;
  //UV_WORK_PRIVATE_FIELDS展开:
  struct uv__work work_req;
};

//涉及到需要线程池处理的请求都会带有这个结构体
struct uv__work {
  void (*work)(struct uv__work *w);//具体的任务函数
  void (*done)(struct uv__work *w, int status);//任务完成之后由loop调用的函数
  struct uv_loop_s* loop;
  void* wq[2];//任务队列
};

相关函数

将任务添加到线程池
int uv_queue_work(uv_loop_t* loop,
                  uv_work_t* req,
                  uv_work_cb work_cb,
                  uv_after_work_cb after_work_cb) {
  if (work_cb == NULL)
    return UV_EINVAL;
  uv__req_init(loop, req, UV_WORK);//初始化req
  req->loop = loop;
  req->work_cb = work_cb;
  req->after_work_cb = after_work_cb;
  //内部处理
  uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done);
  return 0;
}
void uv__work_submit(uv_loop_t* loop,
                     struct uv__work* w,
                     void (*work)(struct uv__work* w),
                     void (*done)(struct uv__work* w, int status)) {
  uv_once(&once, init_once);//初始化线程池,只会执行一次
  w->loop = loop;
  w->work = work;
  w->done = done;
  post(&w->wq);//将任务添加到线程池任务队列
}

初始化线程池

static void init_once(void) {
  unsigned int i;
  const char* val;
  nthreads = ARRAY_SIZE(default_threads);//默认4个线程
  val = getenv("UV_THREADPOOL_SIZE");//可以通过这个环境变量改变
  if (val != NULL)
    nthreads = atoi(val);
  if (nthreads == 0)
    nthreads = 1;//至少一个
  if (nthreads > MAX_THREADPOOL_SIZE)
    nthreads = MAX_THREADPOOL_SIZE;//最多128个
  threads = default_threads;
  if (nthreads > ARRAY_SIZE(default_threads)) {
    threads = uv__malloc(nthreads * sizeof(threads[0]));
    if (threads == NULL) {
      nthreads = ARRAY_SIZE(default_threads);
      threads = default_threads;
    }
  }
  if (uv_cond_init(&cond))
    abort();
  if (uv_mutex_init(&mutex))//初始化互斥量,内部由临界区实现
    abort();
  QUEUE_INIT(&wq);//初始化全局任务队列
  for (i = 0; i < nthreads; i++)
    if (uv_thread_create(threads + i, worker, NULL))
      abort();
  initialized = 1;
}

将任务添加到队列

static void post(QUEUE* q) {
  uv_mutex_lock(&mutex);//锁定
  QUEUE_INSERT_TAIL(&wq, q);//添加到队列末尾
  if (idle_threads > 0)//有线程空闲
    uv_cond_signal(&cond);//唤醒空闲线程中的一个线程
  uv_mutex_unlock(&mutex);
}

每个线程调用的函数

static UINT __stdcall uv__thread_start(void* arg) {
  struct thread_ctx *ctx_p;
  struct thread_ctx ctx;

  ctx_p = arg;
  ctx = *ctx_p;
  uv__free(ctx_p);

  uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
  uv_key_set(&uv__current_thread_key, (void*) ctx.self);//设置线程局部变量,也就是线程句柄

  ctx.entry(ctx.arg);//调用worker
  return 0;
}

线程池内每个线程调用的函数

static void worker(void* arg) {
  struct uv__work* w;
  QUEUE* q;
  (void) arg;

  for (;;) {
    uv_mutex_lock(&mutex);
    while (QUEUE_EMPTY(&wq)) {//没有任务
      idle_threads += 1;//计数加一
      uv_cond_wait(&cond, &mutex);//释放临界区并一直等待
      idle_threads -= 1;//被激活
    }
    q = QUEUE_HEAD(&wq);//取第一个
    if (q == &exit_message)//是退出消息
      uv_cond_signal(&cond);//唤醒线程,如此一来就能唤醒所有等待的线程
    else {
      QUEUE_REMOVE(q);
      QUEUE_INIT(q);  /* Signal uv_cancel() that the work req is
                             executing. */
    }
    uv_mutex_unlock(&mutex);
    if (q == &exit_message)//堆出消息,直接结束线程
      break;
    w = QUEUE_DATA(q, struct uv__work, wq);//获取对应的uv__work
    w->work(w);//调用任务函数,内部会调用用户的任务回调函数
    //向loop发送wake消息,有loop调用done函数
    uv_mutex_lock(&w->loop->wq_mutex);
    w->work = NULL;  /* Signal uv_cancel() that the work req is done
                        executing. */
    QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
    uv_async_send(&w->loop->wq_async);
    uv_mutex_unlock(&w->loop->wq_mutex);
  }
}
取消一个线程池任务
int uv_cancel(uv_req_t* req) {
  struct uv__work* wreq;
  uv_loop_t* loop;

  switch (req->type) {
  case UV_FS:
    loop =  ((uv_fs_t*) req)->loop;
    wreq = &((uv_fs_t*) req)->work_req;
    break;
  case UV_GETADDRINFO:
    loop =  ((uv_getaddrinfo_t*) req)->loop;
    wreq = &((uv_getaddrinfo_t*) req)->work_req;
    break;
  case UV_GETNAMEINFO:
    loop = ((uv_getnameinfo_t*) req)->loop;
    wreq = &((uv_getnameinfo_t*) req)->work_req;
    break;
  case UV_WORK:
    loop =  ((uv_work_t*) req)->loop;
    wreq = &((uv_work_t*) req)->work_req;
    break;
  default:
    return UV_EINVAL;
  }
  return uv__work_cancel(loop, req, wreq);
}
static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
  int cancelled;
  uv_mutex_lock(&mutex);//进入临界区
  uv_mutex_lock(&w->loop->wq_mutex);
  cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
  if (cancelled)//还没被处理,直接从列表中去掉即可
    QUEUE_REMOVE(&w->wq);
  uv_mutex_unlock(&w->loop->wq_mutex);
  uv_mutex_unlock(&mutex);
  if (!cancelled)//正在被处理
    return UV_EBUSY;

  //去掉之后,直接将任务插入loop的任务列表,并发送异步请求唤醒loop,以便loop调用线程池任务的完成回调函数,走完整个流程
  w->work = uv__cancelled;
  uv_mutex_lock(&loop->wq_mutex);
  QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
  uv_async_send(&loop->wq_async);
  uv_mutex_unlock(&loop->wq_mutex);

  return 0;
}

注意,uv_cancel取消一个线程池任务之后,并不是立刻停止了任务,还是会继续走流程,最终还是会由loop所在线程调用任务的完成回调函数,只是完成回调函数中会指明当前任务被取消了,非正常完成。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值