Linux下线程池源码实现

线程池:

初始化阶段创建有最大数量限制的线程,以及一个线程安全的任务队列,若有任务需要处理,则将任务抛入线程池中,线程池中的的线程就会去处理这个任务。
优点
1.避免峰值压力下,资源耗尽的风险;
2.节省线程创建、销毁带来的时间成本

为什么需要线程池?
针对请求处理,单个线程处理,效率过低,采用多线程处理。
但是每个请求都创建一个线程,有可能线程创建过多,效率没有增加反而降低/瞬间资源消耗过度,程序崩溃。因此不能无限制的创建线程处理请求
例如: 处理一个任务,创建一个线程时间t1,处理任务t2,销毁线程t3 t=t1+t2+t3 因此最后能够提前将线程创建好,这些线程不断的去处理即可。

封装实现一个线程池

一堆已经创建好的线程 +线程安全的任务队列。

如何让每一线程针不同的任务,有不同的处理方法,让线程池灵活起来。
向线程池抛入数据的时候,顺便将处理函数一起抛入,线程池中的线程使用函数处理数据即可,最好这个函数由用户自己来定义。

封装任务类:


//线程池中线程获取到一个任务,只需要调用成员函数Run就可以实现,使用用户传入的函数去处理用户的数据。
//而线程池就不用关心改用什么方式处理什么数据了。。
//降低了耦合度:不管任务的处理有任何改变,都跟线程池没有关系,不需要修改线程池的代码
#include<iostream>
#include<queue>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
typedef void (*test_handler_t)(int);

class ThreadTask{

public:
        ThreadTask(int data,task_handler_t handler){
                _data=data;
                _handler=handler;

        }
        void Run(){
                _handler(_data);  //用传入的方法处理传入的数据。
        }
private:
        int _data;      //这是用户传入的要处理的数据
        task_handler_t _handler;   //这个是用户传入的数据的处理方法。

};

class ThreadPool{

public:
        ThreadPool(int max_thread=5){
                        _thr_count=max_thread;
                        pthread_mutex_init(&_mutex,NULL);
                        pthread_cond_init(&_cond,NULL);
                        int i=0;
                        for(;i<_thr_count;i++){
                                pthread_t tid;
                                int ret=pthread_create(&tid,NULL,thr_start,(void *)this );
                                if(ret!=0){
                                        cout<<"create thread error\n";
                                        exit(0);
                                }
                        //若对线程的返回值并不关心,并且希望线程退出后,能够自动释放资源。
                        pthread_detach(tid);   //分离这个线程


        }
        ~ThreadPool(){
                pthread_mutex_destroy(&_mutex);
                pthread_cond_destroy(&_cond);

        }
        bool PushTask(const ThreadTask & task){
                //向线程池外部提供的任务入队操作
                //能够入队的其实都是生产者,因为灭有做队列的最大节点限制,因此生产者不需要阻塞
                //只需要保护task_queue 的操作就可以
                pthread_mutex_lock(&_mutex);
                _task_queue.push(task);
                pthread_mutex_unlock(&_mutex);
                pthread_cond_signal(&_cond);   //唤醒线程池中的线程处理任务             

                return true;

        }
private:
        static  void  * thr_start(void *arg){

                //获取一个任务,然后调用任务对象的Run接口       
                //线程池中的线程并不会处理一个任务就退出,因此是一个死循环。
                ThreadPool * pool =(ThreadPool*) arg;
                while(1){
                        //判断队列是否为空,空则线程需要阻塞等待。
                        pthread_mutex_lock(&pool->_mutex);
                        while(pool->_task_queue.empty()){
                                pthread_cond_wait(&pool->_cond,&pool->_mutex);
                        }
                        ThreadTask task=pool->_task_queue.front(); //获取队首节点
                        pool->__task_queue.pop();    //队首节点出队操作

                        pthread_mutex_unlock(&pool->_mutex);
                //解锁之后再捷信任务处理,否则,会造成当前线程加锁获取任务进行处理期间,其他线程无法获取锁,导致无法处理任务,演变成
                //任务的串行化处理   并且加锁时为了保护task——queue 的操作,而不是为了保护任务处理过程
                task.Run();   //使用任务中用户传入的处理函数处理传入的数据。

                }
                return NULL;
        }

private:
        int _thr_count;   //线程池中的线程的数量
        queue<ThreadTask> _task__queue;
        pthread_mutex_t _mutex;   //互斥保护  _task_queue 的队列
        pthread_cond_t   _cond;   //线程池中的线程等待的队列。  


};
void test(int data){
        //用户自己定义的数据处理函数
        srand(time(NULL));
        int sec=rand()%5;
        printf("thread:%p get data : %d sleep %d sec\n",pthread_self(),data,sec);
        sleep(sec);
        return ;


}
int main(){
        ThreadPool pool;
        int i=0;
        for(i=0;i>10;i++){
                ThreadTask task(i,test);
                pool.PushTask(task);
        }

        while(1){

        sleep(1);
        }
        return 0;
}












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值