Linux下如何实现一个线程池?

[复制链接]
1243|6
 楼主| 问天少年 发表于 2022-12-29 10:24 | 显示全部楼层 |阅读模式
线程池

顾名思义,存储线程的池子。线程池是线程的一种使用模式。在平常业务开发中常规的逻辑是遇到任务然后创建线程去执行。但是线程的频繁创建就类似于内存的频繁申请和销毁,会给操作系统带来大的压力,进而影响整体的性能。所以我们一次申请好一定数量而定线程,然后将线程的管理操作交给线程池,就避免了在短时间内不断创建与销毁线程的代价,线程池不但能够保证内核的充分利用,还能防止过分调度,并根据实际业务情况进行修改。


 楼主| 问天少年 发表于 2022-12-29 10:25 | 显示全部楼层
使用线程池的好处
任务到来后立马就有线程去执行任务,节省了创建线程的时间
防止服务器线程过多导致的系统过载问题
相对于进程池,线程池资源占用较少,但是健壮性很差
降低资源消耗,通过重用已经创建的线程来降低线程创建和销毁的消耗
提高线程的可管理性,线程池可以统一管理、分配、调优和监控其中的线程
 楼主| 问天少年 发表于 2022-12-29 10:25 | 显示全部楼层
什么情况下使用线程池
  • 需要大量的线程来完成任务,且完成任务的时间比较短
  • 对性能要求苛刻的应用
  • 接收突发性的大量请求,但不至于使服务器因此产生大量线程的应用

 楼主| 问天少年 发表于 2022-12-29 10:26 | 显示全部楼层
线程不是越多越好
线程的越多,可能会导致线程切换越频繁, 进而还有可能导致程序运行效率降低。多线程程序的运行效率, 是一个正态分布的结果, 线程数量从1开始增加, 随着线程数量的增加, 程序的运行效率逐渐变高, 直到线程数量达到一个临界值, 再次增加线程数量时, 程序的运行效率会减小(主要是由于频繁的线程切换影响线程运行效率)。

线程若不限制数量的创建,线程创建过多,资源耗尽,有程序崩溃的风险
处理一个短时间任务时,线程会频繁创建和销毁,占用系统资源,降低系统性能
 楼主| 问天少年 发表于 2022-12-29 10:28 | 显示全部楼层
Linux如何实现一个线程池
每个任务在放入任务队列时设置好需要处理的数据和处理函数
线程池中的线程负责从任务队列当中获取任务,并进行处理

代码实现过程
创建一个任务类CTask,可以设置处理任务的回调func以及需要处理的数据m_data
创建一个线程池类CThreadPool,成员变量有设置线程池中线程的最大数量thr_max,任务缓冲队列m_queue,互斥量m_mutex,用于实现对缓冲队列的安全性,条件变量m_cond,用于实现线程池中线程的同步
创建任务类
  1. /* 任务类 */
  2. class CTask
  3. {
  4. public:
  5.     CTask(){}
  6.     ~CTask(){}

  7.     void SetTask(int data, func handler) // 设置数据和处理接口
  8.     {
  9.         m_data = data;
  10.         m_handler = handler;
  11.     }
  12.    
  13.     void Do() // 执行任务
  14.     {
  15.         return m_handler(m_data);
  16.     }

  17. private:
  18.     int  m_data;     // 数据
  19.     func m_handler;  // 处理接口
  20. };

创建线程池类
  1.     /* 创建线程池 */
  2.     for (int i = 0; i < m_SumMax; i++)
  3.     {
  4.         pthread_t tid;
  5.         int ret = pthread_create(&tid, NULL, ThrPoolRun, this);
  6.         if (ret != 0)
  7.         {
  8.             printf("thread create error\n");
  9.         }
  10.     }

任务放入队列
  1.     bool TaskPush(CTask &task)
  2.     {
  3.         pthread_mutex_lock(&m_Mutex);
  4.         m_Queue.push(task);
  5.         pthread_mutex_unlock(&m_Mutex);
  6.         pthread_cond_signal(&m_Mond);
  7.         return true;
  8.     }

线程池空闲线程从队列获取任务并处理
  1.    CThreadPool *p = (CThreadPool*)arg;

  2.     while (p->m_bIsRun)
  3.     {
  4.         pthread_mutex_lock(&p->m_Mutex);

  5.         /* 等待任务到来 */
  6.         while (p->m_Queue.empty())
  7.         {
  8.             pthread_cond_wait(&p->m_Mond, &p->m_Mutex);
  9.         }

  10.         /* 取出任务 */
  11.         CTask Task;
  12.         Task =p->m_Queue.front();
  13.         p->m_Queue.pop();
  14.         pthread_mutex_unlock(&p->m_Mutex);

  15.         /* 处理任务 */
  16.         Task.Do();
  17.     }

main函数
  1. void TaskFunc1(int nData)
  2. {
  3.     printf("TaskFunc1, ThreadId: %p, nData:%d\n", pthread_self(), nData);

  4.     sleep(1);
  5. }

  6. void TaskFunc2(int nData)
  7. {
  8.     printf("TaskFunc2, ThreadId: %p, nData:%d\n", pthread_self(), nData);

  9.     sleep(1);
  10. }

  11. int main(int argc, char const *argv[])
  12. {
  13.     CThreadPool ThreadPool;

  14.     for (size_t i = 0; i < 10; i++)
  15.     {
  16.         CTask Task;

  17.         (0 == (i % 2)) ? Task.SetTask(i, TaskFunc1) : Task.SetTask(i, TaskFunc2);

  18.         ThreadPool.TaskPush(Task);  // 放入任务队列
  19.     }
  20.    
  21.     sleep(3);
  22.     return 0;
  23. }

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 问天少年 发表于 2022-12-29 10:28 | 显示全部楼层
运行结果
10个任务被5个线程分别处理完

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
yangjiaxu 发表于 2022-12-30 21:18 | 显示全部楼层
线程是不是就跟裸机之中的中断操作类似啊?只是线程是应用在系统之中
您需要登录后才可以回帖 登录 | 注册

本版积分规则

79

主题

564

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部