c ++ 11 semi-synchronous achieve half asynchronous thread pool
experience:
With further study, modern c ++ brought me more and more surprises ...
c ++ really become powerful.
Semisynchronous half asynchronous thread pool:
in fact well understood, is divided into three
synchronization layer: multiplexing by IO or other multi-threaded multi-process, etc. will continue to be added to the queue handle the event, the process is carried out simultaneously.
Queuing layer: all pending events are put here. Put on one event here, from here to get the next level event
asynchronous layer: pre-created thread, the thread to continue to handle the task queue layer, the upper layer does not care about them, it is only in charge of the task into the queue, so here is the upper layer is asynchronous.
Supplementary ideas at:
mostly after two
Queue Layer: c ++ 11 may be encapsulated by a function of std :: function for the object, then we also a function of a task is, vector or the like stored by the list container "tasks" for later access to. There will be problems because of competition for resources, so we have to be locked, and to wake up by a condition variable conditions other obstruction in a locked thread, of course, you want to avoid thread blocking can be a waste of resources std :: time_mutex locks with time.
Asynchronous layer: c ++ 11 threads also objects to the package, then we create a thread object container preservation, let them take the task queue layer and execution, execution is not complete but the end of the thread is returned to the container (thread pool).
Look Photo:
If you are not familiar with c ++ content 11 of
the following article is for reference
c ++ multithreading 11
Code :
Synchronous queue:
#include <list> #include <mutex> #include <thread> #include <condition_variable> #include <iostream> template<typename T> class SynQueue { public: SynQueue(int maxsize): m_maxSize(maxsize), m_needStop(false) { } // add an event, the value of copies left and right values of the moving void of Put ( const T & the X-) { // call the private internal interface of the Add the Add (the X-); } void Put(T &&x) { Add(x); } // from the event queue to take, all events take void the Take (STD :: List <T> & List) { // There must wait method unique_lock @ unique_lock wait timer has other functions, lock_guard RAII technique would simply mutex // but slightly lower than the performance unique_lock lock_guard STD unique_lock :: <STD :: the mutex> Locker (m_mutex ); // satisfies condition wake up, is not satisfied blocking m_notEmpty.wait (Locker, [ the this ] { Return m_needStop || NotEmpty (); }); if (m_needStop) return ; List = std :: the Move (m_queue); // wake up other threads blocked mutex m_notFull.notify_one (); } // take an event void the Take (T & t) { std::unique_lock<std::mutex> locker(m_mutex); m_notEmpty.wait(locker, [this] { Return m_needStop || NotEmpty (); }); if (m_needStop) return ; t = m_queue.front(); m_queue.pop_front(); m_notFull.notify_one(); t(); } // stop all the threads read in synchronization queue void Stop () { { std::lock_guard<std::mutex> locker(m_mutex); m_needStop = true ; } m_notFull.notify_all(); m_notEmpty.notify_all(); } // queue is empty BOOL Empty () { std::lock_guard<std::mutex> locker(m_mutex); return m_queue.empty(); } // queue is full BOOL Full () { std::lock_guard<std::mutex> locker(m_mutex); return m_queue.size() == m_maxSize; } // queue size size_t Size () { std::lock_guard<std::mutex> locker(m_mutex); return m_queue.size(); } Private : // add an event to the queue, the event is a paradigm, c ++ 11 we can function as a package by std :: function object. template<typename F> void Add(F &&x) { std::unique_lock<std::mutex> locker(m_mutex); m_notFull.wait(locker, [this] { return m_needStop || NotFull() ; }); if(m_needStop) return; m_queue.push_back(std::forward<F>(x)); m_notEmpty.notify_one(); } // queue under BOOL NotFull () const { bool full = m_queue.size() >= m_maxSize; if(full) :: cout std << " buffer is full, please wait ... " << std :: endl; return ! Full; } // queue is not empty BOOL NotEmpty () const { bool empty = m_queue.empty(); if(empty) { :: cout std << " buffer empty Please wait ... " << std :: endl; std::cout << "线程ID:" << std::this_thread::get_id() << std::endl; } return !empty; } private: :: m_mutex the mutex STD; // mutex STD :: List <T> m_queue; // queue storing tasks STD :: condition_variable m_notEmpty; // queue is not empty condition variable STD :: condition_variable m_notFull; // queue not full condition variable int m_maxSize; // task queue maximum length BOOL m_needStop; // termination identifier };
Thread Pool:
#include <stdio.h> #include <stdlib.h> #include <assert.h> #include <unistd.h> #include "SynQueue.h" #include <functional> #include <thread> #include <memory> #include <atomic> const int MaxTaskCount = 100; class ThreadPool { public : // mandate of type void (), we can achieve an acceptable paradigm of any function by function template template parameter variable c ++ 11, so that a task can accept any task queue up. the using the Task :: = STD function < void ()> ; // hardware_concurrency detection performance hardware, the default number of threads is given the ThreadPool ( int numthreads = STD :: :: Thread hardware_concurrency ()): m_queue(MaxTaskCount) { // initialize the thread, and are managed by shared_ptr Start (numthreads); } // destroy the thread pool ~ ThreadPool ( void ) { Stop(); } // terminate all the threads, call_once to ensure that the function is called only once void Stop () { std::call_once(m_flag, [this] { StopThreadGroup(); }); } // add tasks, the regular version and rvalue reference version void AddTask ( const Task & Task) { m_queue.Put(task); } void AddTask(Task && task) { m_queue.Put(std::forward<Task>(task)); } private: // stop the thread pool void StopThreadGroup () { m_queue.Stop(); m_running = false; for(auto thread : m_threadgroup) { if(thread) thread->join(); } m_threadgroup.clear(); } void Start(int numThreads) { m_running = true; for(int i = 0; i < numThreads; ++i) { // smart pointer management, build parameters and gives a thread, the thread function calls and parameter std :: cout << " the Init the Create the Thread the pool " << std :: endl; m_threadgroup.push_back(std::make_shared<std::thread>(&ThreadPool::RunInThread, this)); } } // first remove the queue all events void RunInThread_list () { while(m_running) { std::list<Task> list; std::cout << "take " << std::endl; m_queue.Take(list); for(auto &task : list) { if(!m_running) return; task(); } } } // once just take one event void RunInThread () { std::cout << m_queue.Size() << std::endl; while(m_running) { Task task; if(!m_running) return; m_queue.Take(task); } } Private : // thread pool std :: List <std :: shared_ptr <std :: the Thread >> m_threadgroup; // task queue SynQueue <Task> m_queue; // atomic Boolean value std :: atomic_bool m_running; // Auxiliary variable - > call_once std :: once_flag M_FLAG; }; int main(int argc, char *argv[]) { ThreadPool pool(2); // Create a thread is added to the task queue task STD :: Thread THD1 ([& the pool] { for ( int I = 0 ; I < 10 ; I ++ ) { auto thdId = std::this_thread::get_id(); pool.AddTask ([thdId] () { std::cout << thdId << " thread execute task" << std::endl; }); } }); std::this_thread::sleep_for(std::chrono::seconds(2)); pool.Stop(); thd1.join(); return EXIT_SUCCESS; }
Reference books:
in-depth application c ++ 11