c ++ 11 semi-synchronous achieve half asynchronous thread pool

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

c ++ 11 smart pointers

c ++ 11 moving objects

c++11 lambda,bind,function

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

Guess you like

Origin www.cnblogs.com/leijiangtao/p/12057422.html