Excerpt from: "In-depth application of c++11", chapter Nineth
In practice, there are two main ways to deal with a large number of concurrent tasks, one is a request by the system to produce a corresponding processing request of the thread (one to another)
The other is that the system pre-generates some process for processing the request, when the requested task is temporarily put into the synchronization queue, assign a process to process the request to process the task,
Threads can also be reused after processing a task, not destroyed, but waiting for the next task to arrive. (One-to-many thread pool technology)
Thread pooling technology avoids the creation and destruction of large numbers of threads, saves resources, and improves the efficiency of parallel processing for multi-core processors due to the allocation of threads to multiple CPUs.
Thread pooling technology is divided into semi-synchronous semi-asynchronous thread pool and leader follower thread pool, with code attached below:
//syncqueue.hpp//Sync queue, hold task #ifndef syncqueue_hpp#defineSyncqueue_hpp#include<list>#include<thread>#include<mutex>#include<condition_variable>#include<utility>#include<iostream>Template<typename t>classsyncqueue{ Public: Syncqueue (intMaxSize): M_maxsize (MaxSize), M_needstop (false){} voidPut (Constt&x) {Std::unique_lock<std::mutex>Locker (M_mutex); M_notfull.wait (locker,[ This]{returnM_needstop | |notfull ();}); if(m_needstop)return; M_queue.push_back (x); M_notempty.notify_one (); } voidTake (std::list<t>&list) {Std::unique_lock<std::mutex>Locker (M_mutex); M_notempty.wait (locker,[ This]{returnM_needstop | |notempty ();}); if(m_needstop) List= Std::move (M_queue);//move semantics,avoid copy.M_notfull.notify_one (); } voidTake (t&x) {Std::unique_lock<std::mutex>Locker (M_mutex); M_notempty.wait (locker,[ This]{returnM_needstop | |notempty ();}); if(m_needstop)return; X=M_queue.front (); M_queue.pop_front (); M_notfull.notify_one (); } voidStop () {{Std::lock_guard<std::mutex>Locker (M_mutex); M_needstop=true; } m_notfull.notify_all (); M_notempty.notify_all (); } std::size_t Size () {Std::lock_guard<std::mutex>Locker (M_mutex); returnm_queue.size (); }Private: BOOLNotfull () {BOOLFull = M_queue.size () >=m_maxsize; if(full) std::cout<<"The buffer is full,waiting...\n"; return!Full ; } BOOLNotempty () {BOOLEmpty =M_queue.empty (); if(empty) std::cout<<"The buffer is empty,waiting...\n"; return!empty; }Private: Std::list<T>M_queue; Std::mutex M_mutex; Std::condition_variable M_notempty; Std::condition_variable M_notfull; intm_maxsize; BOOLM_needstop;//Stop Flag};#endif //sync_queue_hpp
//threadpool.hpp#ifndef thread_pool_hpp#defineThread_pool_hpp#include<list>#include<thread>#include<memory>#include"syncqueue.hpp"#include<functional>#include<atomic>Const intMaxtaskcount = -;classthreadpool{ Public: usingTask = std::function<void() >; ThreadPool (intnumthreads): M_taskqueue (maxtaskcount) {Start (numthreads); } ~ThreadPool () {Stop ();}; voidStop () {std::call_once (m_once_flag,[ This]{stopthreadgroup ();}); } voidAddTask (Consttask&Task) {m_taskqueue.put (Task); } std::size_t Syncqueuesize () {returnm_taskqueue.size (); }Private: voidStart (intnumthreads) {m_running=true; for(inti =0; I < numthreads;++i) {m_threadgrop.push_back (std::make_shared<std::thread> (&threadpool::runinthread, This)); } } voidRuninthread () { while(m_running) {std::list<Task>list; M_taskqueue.take (list); for(auto&task:list) { if(!m_running)return; Task (); } } return; } voidStopthreadgroup () {m_taskqueue.stop (); M_running=false; for(Auto Thread:m_threadgrop) {if(thread) thread-join (); } m_threadgrop.clear (); }Private: Std::list<std::shared_ptr<std::thread>> M_threadgrop;//Thread GroupSyncqueue<task>M_taskqueue; Std::atomic_bool m_running; Std::once_flag M_once_flag;};#endif //thread_pool_hpp
Test:
#include"threadpool.hpp"#include<thread>#include<iostream>#include<chrono>#include<functional>intMain () {ThreadPool Pool (4);//Create threads to handle tasksstd::thread THD1 ([&Pool] { for(inti =0; I <Ten; i++) {Auto Thdid=std::this_thread::get_id (); Pool. AddTask ([thdid]{std::cout<<"thdID1:"<< Thdid <<Std::endl; }); } }); Std::thread THD2 ([&Pool] { for(inti =0; I <Ten; i++) {Auto Thdid=std::this_thread::get_id (); Pool. AddTask ([thdid]{std::cout<<"thdID2:"<< Thdid <<Std::endl; }); } }); Thd1.join (); Thd2.join (); Std::this_thread::sleep_for (Std::chrono::seconds (2)); Pool. Stop (); return 0;}
Developing a semi-synchronous semi-asynchronous thread pool using c++11