C++实现线程池

C++实现线程池

1、背景
多线程编程中,有很多线程处理同样的任务,频繁的创建和销毁线程对系统开销、性能都不友好。利用生产者消费者的思想的,可以把要处理的任务放到一个队列缓冲区里,主线程往缓冲区中队列中添加任务,而工作线程则从队列中取出任务来处理。利用池化思想,就可以把工作线程初始化为一个池,池里有一定数量的工作线程,互斥的从任务队列中取出任务处理。
2、应用场景
主线程往任务队列中添加任务,工作线程取出任务处理。
3、实现方式
两种实现方式,因为多线程涉及到线程间的互斥和同步,这里采取两种实现方式,实现方式一采用Linux提供的互斥锁和信号量。方式二采用C++11提供的互斥和同步的机制。
方式一,基于Linux提供的互斥锁和信号量来实现。

 class handler_t{
 	public:
 		bool operator()(T data){
 			  process(data);
		 }
 };
 class ThreadTask
{
	private:
		int _data;    //要传入的数据
		handler_t _handler; //处理数据的方法
	public:
		void Run()
		{
			_handler(data);
		}
}
#define MAXCAP 3    
class BlockQueue    
{    
 private:    
   std::queue<ThreadTask> q;    
   size_t cap;    
   pthread_mutex_t mutex;    
   pthread_cond_t Cus_cond;    
   pthread_cond_t Pro_cond;    
 public:    
   BlockQueue(size_t c = MAXCAP):cap(c)    
 {    
   //mutex=PTHREAD_MUTEX_INITIALIZER;      //C++不用这个    
   pthread_mutex_init(&mutex,NULL);    
   pthread_cond_init(&Cus_cond,NULL);    
   pthread_cond_init(&Pro_cond,NULL);    
 }    
   ~BlockQueue()                                                                                             
   {    
     pthread_mutex_destroy(&mutex);    
     pthread_cond_destroy(&Cus_cond);    
     pthread_cond_destroy(&Pro_cond);    
   }    
   bool push(const ThreadTask& data)
   {
     //要往缓冲区队列放数据,就得先判断缓冲区是否满了,所有线程都可以访问缓冲区,那么缓冲区就是临界资源
     //需要进行保护
     pthread_mutex_lock(&mutex);
     //循环条件防止时间片调度产生的访问出错
     while(q.size() == cap)
     {
       pthread_cond_wait(&Pro_cond,&mutex);//解锁阻塞加锁
     }
     q.push(data);
     pthread_cond_signal(&Cus_cond);
     pthread_mutex_unlock(&mutex);
     return true;
   }
   bool pop(ThreadTask* data)
   {
     pthread_mutex_lock(&mutex);                                                                             
     while(q.empty() == true)
     {
       pthread_cond_wait(&Cus_cond,&mutex);
     }
     *data= q.front();
     q.pop();
     pthread_cond_signal(&Pro_cond);
     pthread_mutex_unlock(&mutex);
     return true;
   }
};
#define MAX_THREAD 5
#define MAX_QUEUE 10
class threadpool
{
  private:
    int _max_thread;                                                                                          
    BlockQueue _queue;
  private:
    //这个入口函数如果在类中声明,就会自动带有this指针,而入口函数的参数返回值是固定的,将他定义为static
    //就可以解决,但static后就变成了全局的,相当于每个线程调的都是这一个入口函数,也就达不到目的了     
    //将this通过参数传进来就可以解决问题                                                          
    static void* th_entry(void* arg)    
    {                               
      threadpool*pb = (threadpool*)arg;
      while(1)                         
      {       
        ThreadTask task;
        pb->_queue.pop(&task);   //获取到节点
        task.Run();                          
      }            
      return NULL;
    }
  public:
    threadpool(int maxt = MAX_THREAD,int maxq = MAX_QUEUE):_max_thread(maxt),_queue(maxq)
    {
      int ret;
      pthread_t tid[];
      for(int i = 0; i<_max_thread; ++i)
      {
        ret = pthread_create(&tid[i],NULL,th_entry,this);
        if(ret != 0)
        {
          exit(-1);  //构造函数没法判断成功与否,出问题就直接退出进程
        }
        pthread_detach(tid[i]);
      }
    
    }
    bool TaskPush(const ThreadTask& task)                                                                     
    {
      return _queue.push(task);
    }
};

方式二,使用C++11的线程库。

#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <mutex>
#include <condition_variable>
#include <queue>
#include <thread>
#include <functional>
class ThreadPool {
public:
    explicit ThreadPool(size_t threadCount = 8): pool_(std::make_shared<Pool>()) {
            assert(threadCount > 0);
            for(size_t i = 0; i < threadCount; i++) {
                std::thread([pool = pool_] {
                    std::unique_lock<std::mutex> locker(pool->mtx);
                    while(true) {
                        if(!pool->tasks.empty()) {
                            auto task = std::move(pool->tasks.front());
                            pool->tasks.pop();
                            locker.unlock();
                            task();
                            locker.lock();
                        } 
                        else if(pool->isClosed) break;
                        else pool->cond.wait(locker);
                    }
                }).detach();
            }
    }

    ThreadPool() = default;

    ThreadPool(ThreadPool&&) = default;
    
    ~ThreadPool() {
        if(static_cast<bool>(pool_)) {
            {
                std::lock_guard<std::mutex> locker(pool_->mtx);
                pool_->isClosed = true;
            }
            pool_->cond.notify_all();
        }
    }

    template<class F>
    void AddTask(F&& task) {
        {
            std::lock_guard<std::mutex> locker(pool_->mtx);
            pool_->tasks.emplace(std::forward<F>(task));
        }
        pool_->cond.notify_one();
    }

private:
    struct Pool {
        std::mutex mtx;
        std::condition_variable cond;
        bool isClosed;
        std::queue<std::function<void()>> tasks;
    };
    std::shared_ptr<Pool> pool_;
};


#endif //THREADPOOL_H

两种方式需要注意的一点是,线程回调函数的区别,方式一使用普通的phtread_create,作为回调的成员函数要声明为static,避免多传一个this指针。方式二使用了一个lambda表达式来作为线程的一个回调函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值