当前位置:   article > 正文

c/c++ 线程池原理简单代码实现_c++线程池的工作原理

c++线程池的工作原理

1. 线程池原理

       在传统服务器结构中,常用一个总的监听线程监听新用户连接,当有一个新用户进入时,服务器就开启一个新的线程,用于处理这个用户的数据收发,这个线程只服务于这个用户,当用户与服务器端连接关闭以后,服务器将销毁这个线程
       然而频繁地开辟与销毁线程会极大地占用系统资源,线程池的基本思想是提前创建好一些线程,有新任务到来时,则在线程队列中找到一个空闲线程来处理,处理完后线程不退出重回空闲状态继续等待新任务。如果没有空闲线程,则将任务存放到队列, 等待线程池内有线程空闲以后再从任务队列取出任务进行处理。这样就避免了线程创建和销毁的系统资源开销
       线程池应用场景:一个应用要频繁的创建和销毁线程,但任务执行的时间又非常短,这样线程创建和销毁的系统资源开销就不容忽视,这时就可以使用线程池了

2. 实现分析

线程池包含四个部分:

       i. 线程队列,存储创建的多个线程

       ii. 任务队列,存储需要处理的任务,使用 list 链表实现,当有新任务到来时,将节点插入到 list 尾部,当空闲线程读取任务进行处理时,则读取 list 头部节点

       iii. 信号量 sem,指示任务队列中的任务个数,当有新任务加入时,执行 sem_post 操作+1,空闲线程通过 sem_wait 等待任务队列变成非空状态

       iv. 互斥量 mutex, 用于执行添加/移除 list 节点时,进行多线程保护

a. 创建并开始多个线程,线程执行函数是个 while 循环,循环等待任务队列不为空,一旦不为空,则读取 list 头节点,获取任务执行方法和参数,然后执行任务,完成后释放头结点空间

b. 添加新任务到队列,申请新任务节点空间,用于存储新任务执行方法和参数,然后将新任务节点插入到 list 的尾部

3. 代码实现

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <semaphore.h>
  5. #include <pthread.h>
  6. #define MAXNUM_THREAD 3
  7. #define MAXNUM_JOB 10
  8. typedef void* (*Func)(void *arg);
  9. struct job {
  10. Func func;
  11. void *arg;
  12. struct job *next;
  13. };
  14. struct pool {
  15. pthread_t threads[MAXNUM_THREAD];
  16. struct job *head;
  17. pthread_mutex_t mutex; // used for add/remove list node action
  18. sem_t sem; // indicate threads can get one job node from list
  19. };
  20. void* threadFunc(void* arg)
  21. {
  22. Func jobFunc;
  23. void *jobArg;
  24. struct job *head;
  25. struct pool *pl = (struct pool*)arg;
  26. while (1)
  27. {
  28. sem_wait(&(pl->sem)); // wait new job node added to list
  29. pthread_mutex_lock(&(pl->mutex)); // wait other threads complete list action
  30. head = pl->head;
  31. pl->head = pl->head->next; // unlink head node from list, free after func done
  32. pthread_mutex_unlock(&(pl->mutex));
  33. jobFunc = head->func;
  34. jobArg = head->arg;
  35. jobFunc(jobArg);
  36. free(head); // free unlinked head node
  37. }
  38. }
  39. void poolInit(struct pool *pl)
  40. {
  41. pl->head = NULL;
  42. pthread_mutex_init(&(pl->mutex), NULL);
  43. sem_init(&(pl->sem), 0, 0);
  44. for (int i=0; i<MAXNUM_THREAD; i++)
  45. {
  46. pthread_create(&(pl->threads[i]), NULL, threadFunc, (void *)pl);
  47. printf("thread created: %u\n", (unsigned int)(pl->threads[i]));
  48. }
  49. }
  50. void addJob(struct pool *pl, Func func, void *arg)
  51. {
  52. struct job* jobNode = (struct job*)malloc(sizeof(struct job));
  53. jobNode->func = func;
  54. jobNode->arg = arg;
  55. jobNode->next = NULL;
  56. pthread_mutex_lock(&(pl->mutex));
  57. if (NULL == pl->head) // add job node to list tail
  58. {
  59. pl->head = jobNode;
  60. }
  61. else
  62. {
  63. struct job *head = pl->head;
  64. while (head->next)
  65. {
  66. head = head->next;
  67. }
  68. head->next = jobNode;
  69. }
  70. pthread_mutex_unlock(&(pl->mutex));
  71. sem_post(&(pl->sem)); // threads can get job node from list
  72. }
  73. void* jobFunc(void* arg)
  74. {
  75. int index = *((int*)arg);
  76. printf("job: %d started by thread: %u\n", index, (unsigned int)pthread_self());
  77. sleep(rand()%5);
  78. printf("job: %d ended\n", index);
  79. }
  80. int main()
  81. {
  82. int i = 0;
  83. int jobIds[MAXNUM_JOB] = {0};
  84. struct pool pl;
  85. poolInit(&pl);
  86. for (i=0; i<MAXNUM_JOB; i++)
  87. {
  88. jobIds[i] = i;
  89. printf("job: %d added\n", i);
  90. addJob(&pl, jobFunc, (void*)&jobIds[i]); // add job node to list
  91. sleep(rand()%2);
  92. }
  93. for (i=0; i<MAXNUM_THREAD; i++)
  94. {
  95. pthread_join(pl.threads[i], NULL);
  96. }
  97. pthread_mutex_destroy(&(pl.mutex));
  98. sem_destroy(&(pl.sem));
  99. return 0;
  100. }

运行结果如下:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/621826
推荐阅读
相关标签
  

闽ICP备14008679号