首页 > 代码库 > 线程池的使用
线程池的使用
TBOX的线程池通过在每个worker中批量一次拉取多个task,对锁的竞争进行了优化。
由于每个task的函数实现不会太多,所以可以根据每个task的函数地址做hash,统计出每个task执行所花费的平均时间。然后根据这个平均值来动态计算每个worker一次拉取的task的数量,TBOX里面默认每个worker一次拉取10s的task量,这样可以尽可能的避免worker间锁的频繁抢占。
所有从等待队列被拉取出来的task,都会被放到pending队列中去,如果等待队列中的task都被取完了,某个worker处于了空闲状态,就会尝试去pending中,重新拉取其他worker还没有执行到的task, 这样可以解决某些task耗时太长,将worker中剩余的task阻塞住的问题。
重新从pending队列中拉取其他worker的task,并没有通过锁来维护,而是通过原子操作判断task的状态来维护的,所以性能上还是可以保证的。
整个线程池,只用到了一个锁来维护内部的几个队列,每个worker在大部分情况都是独立运行的,只有在自己的所有task都执行完空闲时,才回去全局等待队列中取task,并且上层接口也提供了批量投递任务的接口,来最小化对锁的使用。
下面看下简单的使用例子:
static tb_void_t tb_demo_task_time_done(tb_cpointer_t priv) { tb_msleep((tb_size_t)(priv)); } static tb_void_t tb_demo_task_time_exit(tb_cpointer_t priv) { } /* 投递一个60s的任务到全局线程池 * * tb_thread_pool(): 全局线程池实例,如果不想用全局的,也可以自己创建个线程池 * "60000ms": 指定的一个任务名,常量字符串 * tb_demo_task_time_done: 任务函数地址 * tb_demo_task_time_exit: 任务被执行完或取消的时候的清理函数,可以用于释放一些自有数据,这个是可选的,不用直接传tb_null * (tb_cpointer_t)60000: 传递的私有数据指针,这里简单的传了个等待时间值进去 * tb_false: 是否为紧急任务, 如果为tb_true, 则这个任务会尽可能第一时间优先呗执行 */ tb_thread_pool_task_post(tb_thread_pool(), "60000ms", tb_demo_task_time_done, tb_demo_task_time_exit, (tb_cpointer_t)60000, tb_false); // 投递一个10s的紧急任务 tb_thread_pool_task_post(tb_thread_pool(), "10000ms", tb_demo_task_time_done, tb_null, (tb_cpointer_t)10000, tb_true); // 批量投递两个任务 tb_thread_pool_task_t list[2] = {0}; list[0].name = "60000ms"; list[0].done = tb_demo_task_time_done; list[0].exit = tb_demo_task_time_exit; list[0].priv = (tb_pointer_t)60000; list[0].urgent = tb_false; list[1].name = "10000ms"; list[1].done = tb_demo_task_time_done; list[1].exit = tb_null; list[1].priv = (tb_pointer_t)10000; list[1].urgent = tb_true; tb_thread_pool_task_post_list(tb_thread_pool(), list, 2); // 初始化并且投递一个10s的紧急任务, 返回一个有效句柄 tb_thread_pool_task_ref_t task = tb_thread_pool_task_init(tb_thread_pool(), "10000ms", tb_demo_task_time_done, tb_null, (tb_cpointer_t)10000, tb_true); if (task) { // 取消这个任务,如果这个任务已经在执行中了,就没法取消了 tb_thread_pool_task_kill(tb_thread_pool(), task); // 等待任务取消或完成,超时值:-1:无限等待 tb_thread_pool_task_wait(tb_thread_pool(), task, -1); // 释放这个任务 tb_thread_pool_task_exit(tb_thread_pool(), task); }
如果不想用全局线程池,可以自己初始化一个:
/* 初始化线程池 * * 8:最大worker的数量,上限值,如果传0就是使用默认值 * 0: 每个worker线程的堆栈大小,如果传0就是使用默认值 */ tb_thread_pool_ref_t thread_pool = tb_thread_pool_init(8, 0); if (thread_pool) { // 投递一个10s的紧急任务 tb_thread_pool_task_post(thread_pool, "10000ms", tb_demo_task_time_done, tb_null, (tb_cpointer_t)10000, tb_true); // 如果的调试模式下,可以dump整个线程池的状态和所有处理中的任务状态 #ifdef __tb_debug__ tb_thread_pool_dump(thread_pool); #endif // 等待所有任务执行完成或被取消 tb_thread_pool_task_wait_all(thread_pool, -1); // 退出线程池 tb_thread_pool_exit(thread_pool); }
线程池的使用
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。