The creation and use of common thread pools under Linux (C + +)

Source: Internet
Author: User
Tags class definition semaphore thread class
This paper presents a common thread pool framework, which abstracts tasks related to thread execution in a high-level abstraction, which is independent of specific execution tasks. In addition, the thread pool has dynamic scalability, it can automatically adjust the number of thread pool threads according to the severity of the task. At the end of the article, we'll give you a simple example program, and we'll see how easy it is to perform multithreaded tasks through the thread pool framework. Why do I need a thread poolMost of the current Web servers, including Web servers, email servers, and database servers, all have one thing in common: a large number of connection requests must be processed within a unit of time, but the processing time is relatively short. The server model we used in the traditional multithreaded scenario is that once the request is received, a new thread is created, and the thread executes the task. After the task has finished executing, the thread exits, which is the policy of "create immediately, destroy immediately." Although the time to create a thread has been greatly shortened compared to the creation process, if the task submitted to the thread is execution time is short and the execution is extremely frequent, the server will be in a constant state of creating threads and destroying the threads. We divide the thread execution process in the traditional scenario into three processes: T1, T2, T3. T1: Thread creation time T2: Thread execution time, including thread synchronization time T3: Thread destroy time then we can see that the cost of the thread itself is (T1+T3)/(T1+T2+T3). If the thread executes for a short time, this may account for about 20% to 50% of the cost. This overhead is not negligible if the task is performed frequently. In addition, the thread pool can reduce the number of threads created. Usually the thread pool allows concurrent threads with an upper bound, and if the number of concurrent threads exceeds the upper bound, a portion of the thread will wait. In the traditional scenario, if the number of simultaneous requests is 2000, then the system may need to produce 2000 threads at worst. Although this is not a large number, some machines may not be able to achieve this requirement. So the thread pool appears to be focused on reducing the overhead of the thread pool itself. The thread pool takes a pre-built technique and, after the application starts, creates a number of threads (N1) immediately and puts it into the idle queue. These threads are in a blocking (suspended) state, do not consume the CPU, but occupy a small amount of memory space. When the task arrives, the buffer pool selects an idle thread and runs the task into this thread. When N1 threads are working on a task, the buffer pool automatically creates a number of new threads to handle more tasks. The thread does not quit after the task has finished executing, but continues to remain in the pool waiting for the next task. When the system is more idle, most of the threads have been paused, the thread pool automatically destroys some of the threads and reclaims the system resources. Based on this pre-built technology, the thread pool distributes the overhead of threading creation and destruction itself to individual tasks, and the more executions, the less the thread itself spends on each task, but we may also need to consider the overhead of synchronizing between threads. building a thread pool frameworkThe general thread pool must have the following components: Thread pool Manager: Used to create and manage thread pool worker threads: The thread pool is actually executing the threading task interface: Although the thread pool is mostly used to support network servers, we abstract the tasks that the thread performs into the task interface, The thread pool is independent of the specific task. Task queues: The concept of a thread pool can be specific to the implementation of a queue, a data structure such as a list, in which the execution thread is saved. The universal thread pool Framework We implement consists of five important parts cthreadmanage,cthreadpool,cthread,cjob,cworkerthread, In addition, the framework includes classes Cthreadmutex and ccondition that are used by thread synchronization. Cjob is the base class for all tasks that provide an interface run, and all task classes must inherit from that class while implementing the Run method. The specific task logic is implemented in this method. Cthread is a Linux thread wrapper that encapsulates the properties and methods most often used by Linux threads, an abstract class that is the base class for all thread classes and has an interface run. CWorkerThread is a thread class that is actually scheduled and executed, which inherits from Cthread and implements the Run method in Cthread. CThreadPool is a thread pool class that is responsible for saving threads, freeing threads, and scheduling threads. Cthreadmanage is a direct interface between the thread pool and the user, which masks the concrete implementation of the internal. Cthreadmutex is used for mutual exclusion between threads. Ccondition is the encapsulation of the conditional variable, used for synchronization between threads. The inheritance relationship of their classes is shown in the following illustration: The sequence of thread pools is simple, as shown in the following illustration. Cthreadmanage deals directly with clients, accepting the initial number of threads that need to be created and accepting the tasks that the client submits. The task here is a concrete, non-abstract task. The inside of the cthreadmanage is actually called CThreadPool related operations. CThreadPool Create specific threads and distribute the tasks submitted by the client to Cworkerthread,cworkerthread to actually perform specific tasks. Understanding System ComponentsLet's take a look at each component in the system separately. Cthreadmanage The Cthreadmanage function is very simple, it provides the simplest method, its class definition is as follows: Class Cthreadmanage {private:     cthreadpool*     M_pool;     int          M_numofthread; Protected:public:     void     setparallelnum (int num);     Cthreadmanage ();     cthreadmanage (int num);     virtual ~cthreadmanage ();       void    Run (cjob* job,void* jobdata);     void    terminateall (void); }; Where M_pool points to the actual thread pool; M_numofthread is the number of concurrent threads that are allowed to be created at the initial creation time. The run and Terminateall method is also very simple, just a simple call to cthreadpool some related methods. Its specific implementation is as follows: Cthreadmanage::cthreadmanage () {    m_numofthread = ten     M_pool = new CThreadPool (M_numofthread); &NBSP} cthreadmanage::cthreadmanage (int num) {    m_numofthread = num;     m_pool = new CT Hreadpool (M_numofthread); } cthreadmanage::~cthreadmanage () {&Nbsp;   if (NULL!= m_pool)     Delete m_pool; } void cthreadmanage::setparallelnum (int num) {    m_numofthread = num;} void Cthreadmanage::run (cjob* Jo b,void* jobdata) {    m_pool->run (job,jobdata);} void Cthreadmanage::terminateall (void) {     M_pool->terminateall (); } Cthread The cthread  class implements the encapsulation of the Linux thread operation, which is the base class for all threads and an abstract class that provides an abstract interface run, and all cthread must implement the Run method. The Cthread definition looks like this: class Cthread {private:     int          m_ Errcode;     semaphore    m_threadsemaphore; //the Inner semaphore, which-used to realize & nbsp;   unsigned     long m_threadid;        bool          m_detach;      //the thread is detached      BOOL         m_createsuspended; //if suspend after creating      char*        M_threadname;     ThreadState m_threadstate;     //the State of the thread protected:      void     seterrcode (int errcode) {m_errcode = Errcode;}     static void* Threadfunction (void*); Public:     Cthread ();     Cthread (bool Createsuspended,bool detach);     virtual ~cthread ();     virtual void Run (void) = 0;     void     setthreadstate (threadstate state) {m_threadstate = state;}        bool     Terminate (void);   //terminate the Threa     BOOL & nbsp;   Start (void);       //start to execute the thread      void     Exit (void);     bool     Wakeup (void);         threadstate getthreadstate (void) {return m_threadstate;}      int      GetLastError (void) {return m_errcode;}     void      SetThreadName (char* thrname) {strcpy (m_threadname,thrname);}     char*    Getthreadname (void) {return m_ThreadName;}     int      getthreadid (void) {return m_threadid;}        BOOL     setpriority (int priority);     int      getpriority (void);     int      getconcurrency (void);     void     setconcurrency (int num);     bool     Detach (void);     bool     Join (void);     bool     Yield (void);     int      Self (void); }; The state of a thread can be divided into four types, idle, busy, suspended, terminated (including normal exit and abnormal exit). Because the current Linux line threading does not support pending operations, our pending operation here is similar to a pause. If the thread does not want to perform the task immediately after it is created, then we can "pause" it and wake if it needs to be run. It is important to note that once a thread begins to perform a task, it cannot be suspended and will continue to perform the task to completion. The related operation of the thread class is very simple. The thread's execution entry begins with the start () function, which calls the function threadfunction,threadfunction and then calls the actual run function to perform the actual task.   CThreadPool CThreadPool is the bearer container of a thread, which can generally be implemented as a stack, a one-way queue, or a two-way queue. In our system we use STL vectors to save threads. The implementation code for CThreadPool is as follows: Class CThreadPool {friend class CWorkerThread; private:     unsigned int m_maxnum;&nb sp; //the max thread num, can create at the same time     unsigned int m_availlow; The min num of idle thread that shoule kept     unsigned int m_availhigh;   //the max num of idle thread that kept in the same time     unsigned int m_availnum; The normal thread num of idle num;     unsigned int m_initnum; //normal thread num; Protected:     cworkerthread* getidlethread (void);       void    appendtoidlelist (cworkerthread* jobthread);     void    movetobusylist (cworkerthread* idlethread);     void    movetoidlelist (cworkerthread* busythread);       void    Deleteidlethread (int num);     void    createidlethread (int num); Public:     Cthreadmutex m_busymutex;   //when visit busy List,use to lock and Unlock     cthreadmutex m_idlemutex;   //when visit idle list,use M_idlemutex to lock and Unlock     Cthreadmutex M_jobmutex; When visit job List,use M_jobmutex to lock and unlock     Cthreadmutex M_varmutex;       ccondition       M_busycond; M_busycond is used to sync busy thread list     ccondition       m_ Idlecond; M_idlecond is used to sync idle thread list     ccondition       m_ Idlejobcond; //m_jobcond is used to sync job list     ccondition        M_maxnumcond;       VECTOR&LT;CWORKERTHREAD*&GT;&NBsp;  m_threadlist;     vector<cworkerthread*>   m_busylist;    //Thread List     vector<cworkerthread*>   m_idlelist; Idle List       CThreadPool ();     cthreadpool (int initnum);     virtual ~cthreadpool ();       void    setmaxnum (int maxnum) {m_maxnum = maxnum;}     int      getmaxnum (void) {return m_maxnum;}     void    Setavaillownum (int minnum) {m_availlow = Minnum;}     int     getavaillownum (void) {return m_availlow;}     void     setavailhighnum (int highnum) {m_availhigh = Highnum;}     int      Getavailhighnum (void) {return m_availhigh;}     int     Getactualavailnum ( void) {return m_availnum;}     Int     getallnum (void) {return m_threadlist.size ();}     int     Getbusynum (void) {return m_busylist.size ();}     void    setinitnum (int initnum) {m_ Initnum = Initnum;}     int     getinitnum (void) {return m_initnum;}        void    terminateall (void);     void    Run (cjob* job,void* jobdata); }; Cthreadpool::cthreadpool () {    m_maxnum = n     m_availlow = 5;     m_in Itnum=m_availnum =;       M_availhigh = 20;       m_busylist.clear ();     m_idlelist.clear ();     for (int i=0;i<m_initnum;i++) {    cworkerthread* thr = new CWorkerThread ();      Thr->setthreadpool (this);     appendtoidlelist (THR);     Thr->start ();    }   cthreadpool::cthreadpool (int initnum) {    assert (initnum>0 && INITNUM&LT;=30);     m_maxnum   = 30;     M_availlow = initnum-10>0?initnum-10:3;     m_initnum=m_availnum = Initnum;       m_availhigh = initnum+10;       m_busylist.clear ();     m_idlelist.clear ();     for (int i=0;i<m_initnum;i++) {    cworkerthread* thr = new CWorkerThread ();      appendtoidlelist (THR);     Thr->setthreadpool (this);     Thr->start ();      //begin the thread,the thread wait for job    }   Cthreadpool::~cthreadpool () {   terminateall ();}   void Cthreadpool::termi Nateall () {    for (int i=0;i < m_threadlist.size (); i++) {    cworkerthread* thr = M_thr EadlIst[i];     Thr->join ();    }     return; }   cworkerthread* Cthreadpool::getidlethread (void) {    while (m_idlelist.size () ==0)      m_idlecond.wait ();         M_idlemutex.lock ();     if (m_idlelist.size () > 0)     {    cworkerthread* thr = (cworkerthr ead*) M_idlelist.front ();     printf ("Get Idle thread%d/n", Thr->getthreadid ());     M_idlemutex.unlock ();     return thr;    }     M_idlemutex.unlock ();       return NULL; }  //add a idle thread to idle list void Cthreadpool::appendtoidlelist (cworkerthread* jobthread) {  &nbs P M_idlemutex.lock ();     M_idlelist.push_back (Jobthread);     M_threadlist.push_back (Jobthread);     M_idlemutex.unlock (); }  //move and IDle thread to Busy thread void Cthreadpool::movetobusylist (cworkerthread* idlethread) {    m_ Busymutex.lock ();     M_busylist.push_back (Idlethread);     m_availnum--;     M_busymutex.unlock ();        M_idlemutex.lock ();     Vector<cworkerthread*>::iterator POS;     pos = Find (M_idlelist.begin (), M_idlelist.end (), idlethread);     if (pos!=m_idlelist.end ())     m_idlelist.erase (POS);     M_idlemutex.unlock (); }   void Cthreadpool::movetoidlelist (cworkerthread* busythread) {    m_idlemutex.lock ();  & nbsp;  M_idlelist.push_back (Busythread);     m_availnum++;     M_idlemutex.unlock ();       M_busymutex.lock ();     Vector<cworkerthread*>::iterator POS;     pos = Find (M_busylist.begin (), M_busylist.end (), Busythread);     if (Pos!=m_busylist.end ())     m_busylist.erase (POS);     M_busymutex.unlock ();       m_idlecond.signal ();     m_maxnumcond.signal (); }  //create num idle thread and put them to idlelist void cthreadpool::createidlethread (int num) {  &nbsp ; for (int i=0;i<num;i++) {    cworkerthread* thr = new CWorkerThread ();     thr-> Setthreadpool (this);     appendtoidlelist (THR);     M_varmutex.lock ();     m_availnum++;     M_varmutex.unlock ();     Thr->start ();      //begin the thread,the thread wait for job    }   void CThreadPool::D eleteidlethread (int num) {    printf (Enter into Cthread Pool::D eleteidlethread/n ");     M_idlemutex.lock ();     printf ("Delete num is%d/n", num);     for (int i=0;i<num;i++) {    cworkerthread* thr     if (m_idlelist.size () > 0 ) {            thr = (cworkerthread*) m_idlelist.front ();             printf ("Get Idle thread%d/n",thr-> GetThreadId ());    }
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.