转载本文请联系程序大师喵公众号。之前分享过一个手写的线程池-C语言版,后来有朋友问有没有C++线程池实现的文章:其实我很早以前就写过一篇C++线程池的文章,不过估计很多新朋友都有从来没有见过它。这里也转发!在开发过程中经常会遇到需要使用线程池的情况,但是看了一圈之后发现C++中完整的线程池第三方库还是比较少,所以打算自己搭建一个。链接地址附在文末,目前只是第一版,可能还有很多问题,还请大家指正。线程池需要什么功能?我个人认为线程池需要支持以下基本功能:核心线程(core_threads):线程池中的最小线程数。线程将在初始化期间创建并驻留在线程池中。最大线程数(max_threads):线程池的最大线程数,max_threads>=core_threads,当任务数过多线程池无法执行时,会在内部创建更多的线程来执行更多的任务,内部线程数不会超过max_threads,创建的线程在一段时间内不执行任务会自动回收,线程数最终会保持在核心线程数。超时(time_out):上面说了,创建的线程如果在time_out时间内没有执行任务,就会被回收。可以获得当前线程池的线程总数。可以获得当前线程池中空闲线程的数量。启用线程池功能的开关。关闭线程池功能的开关可以选择是否立即关闭。当立即关闭线程池时,缓存在当前线程池中的任务将不会被执行。线程池如何实现?下面是自己实现的线程池逻辑。线程池中的主要数据结构1.链表或数组:用于存储线程池中的线程。2、队列:用于存放线程池中需要执行的任务。3、条件变量:当有任务要执行时,用于通知等待线程从任务队列中取出任务执行。代码如下:classThreadPool{public:usingPoolSeconds=std::chrono::seconds;/**线程池配置*core_threads:核心线程数,线程池最小线程数,初始化会创建好的threads,常驻线程池**max_threads:>=core_threads,当任务数量过多,线程池无法执行时,*会在内部创建更多的线程来执行更多的任务,内部线程数量不会exceedmax_threads**max_task_size:内部允许存储的最大任务数,尚未使用**time_out:Cache线程的超时时间,Cache线程指的是max_threads-core_threads的线程,*没有任务执行时在time_out时间内,这个线程会被自动回收*/structThreadPoolConfig{intcore_threads;intmax_threads;intmax_task_size;PoolSecondstime_out;};/***线程状态:waiting,running,stop*/enumclassThreadState{kInit=0,kWaiting=1,k运行=2,kStop=3};/***线程类型识别:表示该线程是核心线程还是Cache线程,内部临时创建Cache执行更多任务*/enumclassThreadFlag{kInit=0,kCore=1,kCache=2};usingThreadPtr=std::shared_ptr;usingThreadId=std::atomic;usingThreadStateAtomic=std::atomic;usingThreadFlagAtomic=std::atomic;/***threadpool线程存在的基本单位,每个线程都有一个自定义的ID,线程类型标识和状态*/structThreadWrapper{ThreadPtrptr;ThreadIdid;ThreadFlagAtomicflag;ThreadStateAtomicstate;ThreadWrapper(){ptr=nullptr;id=0;state.store(ThreadState::kInit);}};usingThreadWrapperPtr=std::shared_ptr;usingThreadPoolLock=std::unique_lock;私有:ThreadPoolConfigconfig_;std::listworker_threads_;std::queue>tasks_;std::mutexask_mutex_;std::condition_variabletask_cv_;std::atomictotal_function_num_;std::atomicwaiting_thread_num_;std::atomicthread_id_;//用于给新创建的线程分配IDstd::atomicis_shutdown_now_;std::atomicis_shutdown_;std::atomicis_available_;};线程池的初始化在构造函数中为每个成员变量附加初始值,同时判断线程池的config是否合法ThreadPool(ThreadPoolConfigconfig):config_(config){this->total_function_num_.store(0);this->waiting_thread_num_.store(0);this->thread_id_.store(0);this->is_shutdown_.store(false);this->is_shutdown_now_.store(false);if(IsValidConfig(config_)){is_available_.store(true);}else{is_available_.store(false);}}boolIsValidConfig(ThreadPoolConfigconfig){if(config.core_threads<1||config.max_threads0){AddThread(GetNextThreadId());}cout<<"Initthreadend"<is_shutdown_now_.store(true);}else{this->is_shutdown_.store(true);}this->task_cv_.notify_all();is_available_.store(false);}}如何向线程池中添加线程?参见AddThread()函数,默认会创建Core线程,也可以选择创建Cache线程。线程内部会死循环,不停的等待任务,有任务来就执行。同时内部会判断是否是Cache线程。如果是CacheThread,如果超时时间内没有任务执行,会自动退出循环,线程结束。这里也检查is_shutdown和is_shutdown_now标志位,根据这两个标志位是否为真来判断是否结束线程。voidAddThread(intid){AddThread(id,ThreadFlag::kCore);}voidAddThread(intid,ThreadFlagthread_flag){cout<<"AddThread"<(thread_flag)<();thread_ptr->id.store(id);thread_ptr->flag.store(thread_flag);autofunc=[this,thread_ptr](){for(;;){std::functiontask;{ThreadPoolLocklock(this->task_mutex_);if(thread_ptr->state.load()==ThreadState::kStop){break;}cout<<"threadid"<id.load()<<"runningstart"<state.store(ThreadState::kWaiting);++this->waiting_thread_num_;boolis_timeout=false;if(thread_ptr->flag.load()==ThreadFlag::kCore){this->task_cv_.wait(lock,[this,thread_ptr]{return(this->is_shutdown_||this->is_shutdown_now_||!this->tasks_.empty()||thread_ptr->state.load()==ThreadState::kStop);});}else{this->task_cv_.wait_for(lock,this->config_.time_out,[this,thread_ptr]{return(this->is_shutdown_||this->is_shutdown_now_||!this->tasks_.empty()||thread_ptr->state.load()==ThreadState::kStop);});is_timeout=!(this->is_shutdown_||this->is_shutdown_now_||!this->tasks_.empty()||thread_ptr->state.load()==ThreadState::kStop);}--this->waiting_thread_num_;cout<<"threadid"<id.load()<<"runningwaitend"<state.store(ThreadState::kStop);}if(thread_ptr->state.load()==ThreadState::kStop){cout<<"threadid"<id.load()<<"statestop"<is_shutdown_&&this->tasks_.empty()){cout<<"threadid"<id.load()<<"shutdown"<is_shutdown_now_){cout<<"threadid"<id.load()<<"shutdownnow"<state.store(ThreadState::kRunning);task=std::move(this->tasks_.front());this->tasks_.pop();}task();}cout<<"threadid"<id.load()<<"runningend"<ptr=std::make_shared(std::move(func));if(thread_ptr->ptr->joinable()){thread_ptr->ptr->detach();}this->worker_threads_。emplace_back(std::move(thread_ptr));}如何将任务放入线程池执行?看下面的代码,使用std::bind将任务封装成std::function放入任务队列中。它会判断是否有空闲线程。如果没有空闲线程,它会自动创建最多(max_threads-core_threads)个缓存线程来执行任务//放在线程序池中执行函数templateautoRun(F&&f,Args&&...args)->std::shared_ptr>>{if(this->is_shutdown_.load()||this->is_shutdown_now_.load()||!IsAvailable()){returnnullptr;}if(GetWaitingThreadSize()==0&&GetTotalThreadSize();autotask=std::make_shared>(std::bind(std::forward(f),std::forward(args)...));total_function_num_++;std::futureres=task->get_future();{ThreadPoolLocklock(this->task_mutex_);this->tasks_.emplace([task](){(*task)();});}this->task_cv_.notify_one();returnstd::make_shared>>(std::move(res));}如何获取当前线程序池中线程序的总个数?intGetTotalThreadSize(){returnthis->worker_threads_.size();}如何获取当前线程池的空闲线程数?waiting_thread_num的值表示空闲线程的个数,这个变量会在线程循环内部更新intGetWaitingThreadSize(){returnthis->waiting_thread_num_.load();}简单的测试代码intmain(){cout<<"hello"<index;index.store(0);std::threadt([&](){for(inti=0;i<10;++i){pool.Run([&](){cout<<"function"<