Linux-C编程 / 多线程 / 一个简洁可靠的线程池实现

核心 API 的实现

1. thpool_init()

该函数用于创建一个线程池,先明确线程池的定义:

 
  1. typedef struct thpool_{

  2.  thread**   threads;                  /* pointer to threads        */

  3.  volatile int num_threads_alive;      /* threads currently alive   */

  4.  volatile int num_threads_working;    /* threads currently working */

  5.  pthread_mutex_t  thcount_lock;       /* used for thread count etc */

  6.  pthread_cond_t  threads_all_idle;    /* signal to thpool_wait     */

  7.  jobqueue  jobqueue;                  /* job queue                 */

  8. } thpool_;

thpool_init() 的实现思路:

  1. 分配 struct thpool_:

  • malloc(sizeof(struct thpool_))

  • 初始化 struct thpool_;

    • malloc(num_threads * sizeof(struct thread *))

    • thread_init(thpool_p, &thpool_p->threads[n], n);

    • jobqueue_init(&thpool_p->jobqueue)

    • 初始化 jobqueue:

    • 创建用户指定数目的线程,用一个二级指针来指向这一组线程;

  • 返回 struct thpool_ *;

  • 2. thpool_add_work()

    该函数用于往线程池里添加一个任务,先明确任务的定义:

     
      
    1. typedef struct job{

    2.  struct job*  prev; /* pointer to previous job */

    3.  void   (*function)(void* arg);  /* function pointer */

    4.  void*  arg;  /* function's argument */

    5. } job;

    程序里是用队列来管理任务的,这里的 job 首先是一个队列节点,携带的数据是 function + arg。

    thpool_add_work 的实现思路:

    1. 分配 struct job:

    • malloc(sizeof(struct job))

  • 初始化 struct job;

    • newjob->function=function_p;

    • newjob->arg=arg_p;

  • 添加到队列中:

    • jobqueue_push(&thpool_p->jobqueue, newjob);

    3. thpool_pause() 和 thpool_resume()

    thpool_pause() 用于暂停所有的线程,通过信号机制来实现:

     
      
    1. void thpool_pause(thpool_* thpool_p) {

    2.  int n;

    3.  for (n=0; n < thpool_p->num_threads_alive; n++){

    4.   pthread_kill(thpool_p->threads[n]->pthread, SIGUSR1);

    5.  }

    6. }

    给所有工作线程发送 SIGUSR1,该信号的处理行为就是让线程休眠:

     
      
    1. static void thread_hold(int sig_id) {

    2.     (void)sig_id;

    3.  threads_on_hold = 1;

    4.  while (threads_on_hold){

    5.   sleep(1);

    6.  }

    7. }

    只需要 thpool_resume() 中,将 threads_on_hold = 0,就可以让线程返回到原来被中止时的工作状态。

    4. thpool_wait()

    wait 的实现比较简单,只要还有任务或者还有线程处于工作状态,就执行 pthread 的 wait 操作:

     
      
    1. while (thpool_p->jobqueue.len || thpool_p->num_threads_working) {

    2.   pthread_cond_wait(&thpool_p->threads_all_idle, &thpool_p->thcount_lock);

    3.  }

    到此,我感觉已经没有太多难点了,感兴趣的小伙伴们可以自行查阅源码。

    四、测试用例

    优秀的开源项目通常会附带丰富的测试用例,此项目也不例外:

    • memleaks.sh:测试是否发生内存泄露;

    • threadpool.sh: 测试线程池是否能正确地执行任务;

    • pause_resume.sh:测试 pause 和 resume 是否正常;

    • wait.sh:测试 wait 功能是否正常;

    • heap_stack_garbage:测试堆栈内有垃圾数据时的情况;

    思考技术,也思考人生

    要学习技术,更要学习如何生活

    最近在看的书:

    《精要主义》

    收获了什么?

    身体是一种资产:

    • 身体是用来达到个人贡献峰值的珍贵资产,而最常见用来破坏这种资产的方式是:缺乏睡眠。

    • 有的人可以很轻易地让自己拼命工作,并且认为自己强大到可以通过减少睡眠来尽快实现自己的目标。而事实是,他们绝大多数人只是习惯了疲惫状态,以至于已经忘记充分休息后的高效学习、工作是什么感觉。

    • 正确的做法是:系统地、有意识地为睡眠留下一席之地,为每天的生活保留一部分精力和创造力、解决问题的能力,以应对一些意外情况。

    你和我各有一个苹果,如果我们交换苹果的话,我们还是只有一个苹果。但当你和我各有一个想法,我们交换想法的话,我们就都有两个想法了。

    觉得文章对你有价值,不妨点个 在看和赞

点击查看大图

Linux-C编程 / 多线程 / 一个简洁可靠的线程池实现-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值