【Linux】一篇文章搞定 线程池

╰半橙微兮° 2023-01-05 14:13 207阅读 0赞

线程池

    1. 线程池的概念
    1. Linux下线程池的CPP模拟实现

1. 线程池的概念

  • 线程池的本质:一个线程安全队列 + 一堆线程
  • 线程安全队列中的元素类型: 类型 = 数据 + 该数据处理方式

图解
在这里插入图片描述

2. Linux下线程池的CPP模拟实现

  • 数据处理该数据的方法封装成一个数据类,并提供一个run方法,调用数据处理方法处理数据
  • 主线程负责向线程池安全队列插入数据
  • 线程池中的工作线程负责从安全队列拿出数据,并用数据类提供的run方法,让数据自己处理自己

    include

    include

    include

    include

    include

    include

    using namespace std;

    //函数指针的宏定义
    typedef void (*Handler)(int);

    template
    class QueueData{

    1. public:
    2. //传入数据和处理数据的函数
    3. QueueData(T data_,Handler handler_)
    4. {
    5. data = data_;
    6. handler = handler_;
    7. }
    8. ~QueueData(){ }
    9. //调用run函数来使用传入的函数处理传入的数据
    10. void run()
    11. {
    12. handler(data);
    13. }
    14. private:
    15. T data; //数据
    16. Handler handler; //处理数据的方法

    };
    template
    class ThreadPool{

    1. public:
    2. //初始化线程池 并按照传入 线程数量 创建 相应个数的线程
    3. ThreadPool(int Capacity,int Thread_count)
    4. {
    5. //初始化 队列容量+线程数量+互斥锁+条件变量+退出标志
    6. capacity = Capacity;
    7. thread_count = Thread_count;
    8. lock = PTHREAD_MUTEX_INITIALIZER;
    9. consumer_cond = PTHREAD_COND_INITIALIZER;
    10. flag = false;
    11. //创建线程
    12. pthread_t ptid;
    13. for(int i = 0; i < thread_count; i++)
    14. {
    15. int ret = pthread_create(&ptid,NULL,PoolStart,(void*)this);
    16. if(ret < 0)
    17. perror("pthread_create");
    18. }
    19. }
    20. ~ThreadPool()
    21. {
    22. // 销毁 条件变量+互斥锁
    23. pthread_mutex_destroy(&lock);
    24. pthread_cond_destroy(&consumer_cond);
    25. }
    26. //主线程调用 向队列中插入数据
    27. void Push(QueueData<T>* qd)
    28. {
    29. pthread_mutex_lock(&lock);
    30. if(flag) //
    31. {
    32. pthread_mutex_unlock(&lock);
    33. return;
    34. }
    35. safe_queue.push(qd);
    36. pthread_mutex_unlock(&lock);
    37. pthread_cond_signal(&consumer_cond); //提醒PCB等待队列中的线程可以来取数据啦
    38. }
    39. //调用该函数表示数据处理完了 可以退出所有线程了
    40. void ThreadExit()
    41. {
    42. pthread_mutex_lock(&lock);
    43. flag = true;
    44. pthread_mutex_unlock(&lock);
    45. pthread_cond_broadcast(&consumer_cond);
    46. }
    47. private:
    48. queue<QueueData<T>* > safe_queue; //队列
    49. size_t capacity; //安全队列中最大容量
    50. pthread_mutex_t lock; //保证主线程与消费线程之间互斥
    51. pthread_cond_t consumer_cond; //保证消费线程之间同步
    52. size_t thread_count; //线程池中的线程数量
    53. bool flag; //线程是否可以退出的标志
    54. //工作线程调用
    55. void Pop(QueueData<T>** qd)
    56. {
    57. (*qd) = safe_queue.front(); //将安全队列中的数据放入参数中
    58. safe_queue.pop(); //将队首元素弹出
    59. }
    60. //线程入口函数中调用Pop函数,将this指针传入进来
    61. static void* PoolStart(void* arg)
    62. {
    63. //线程分离,线程退出后OS自动回收其资源
    64. pthread_detach(pthread_self());
    65. //将void*类型的参数强转成ThreadPool*
    66. ThreadPool* p = (ThreadPool*)arg;
    67. //工作线程的任务就是取出数据并处理数据
    68. while(1)
    69. {
    70. //为了保证线程能够独占式访问共享资源,须加锁
    71. pthread_mutex_lock(&p->lock);
    72. while(p->safe_queue.empty())
    73. {
    74. if(p->flag) //当flag为true时表示数据处理完了 该线程可以退出了
    75. {
    76. (p->thread_count)--;
    77. pthread_mutex_unlock(&p->lock);
    78. pthread_exit(NULL);
    79. }
    80. pthread_cond_wait(&p->consumer_cond,&p->lock); //当队列空就等待并释放锁
    81. }
    82. QueueData<T>* qd;
    83. p->Pop(&qd); //从安全队列中拿出来数据
    84. //先释放锁 再 处理数据,反之,会导致处理完数据再释放锁,释放锁时间过长
    85. pthread_mutex_unlock(&p->lock);
    86. qd->run();
    87. }
    88. }

    };

    //处理数据的函数
    void DealData(int data)
    {

    1. printf("%d\n",data);

    }

    int main()
    {

    1. //创建线程池,设置安全队列中最多可以保存4个元素,线程数量规定为4个
    2. ThreadPool<int>* tp = new ThreadPool<int>(4,4);
    3. if(!tp) return -1;
    4. //假设需要处理 100 个数据
    5. for(int i = 0; i < 100; i++)
    6. {
    7. QueueData<int>* qd = new QueueData<int>(i,DealData);
    8. if(!qd) continue;
    9. tp->Push(qd);
    10. }
    11. sleep(3);
    12. //退出线程池
    13. tp->ThreadExit();
    14. return 0;

    }

发表评论

表情:
评论列表 (有 0 条评论,207人围观)

还没有评论,来说两句吧...

相关阅读

    相关 文章懂多线

    目录 一、基本概念 二、线程的创建 三、线程的生命周期 四、线程的编号和名称 五、常用的方法 六、线程同步机制 -------------------- 前言