Thread Pool analysis and C ++ code implementation
(1) What is a thread pool?
Thread pool is a multi-thread processing technology. Several threads are created in the thread pool and managed. When a new task arrives, add the task to a created idle thread for execution. The thread pool has the same priority. Therefore, it is not recommended that you use a thread pool for tasks with a specific thread priority.
(2) advantages and applications of the thread pool
The thread pool manages threads in a unified manner, which reduces the System Scheduling overhead for frequent thread creation and destruction, and greatly improves the server's performance in processing concurrent tasks.
The thread pool is suitable for frequent task scheduling, such as handling HTTP requests, multiple tasks, and a small task cycle.
(3) c ++ code implementation
# Include "stdafx. H"
# Include "stdafx. H"
# Include <assert. h>
# Include <windows. h>
# Include <map>
# Include <iostream>
Using namespace STD;
Class itask
{
Public:
Virtual void processtask (void * puser) = 0;
};
// Failover pool
Class cthreadpool
{
Public:
Class threadinfo
{
Public:
Threadinfo () {m_hthread = 0; m_bbusyworking = false ;}
Threadinfo (handlehandle, boolbbusy) {m_hthread = handle; m_bbusyworking = bbusy ;}
Threadinfo (const threadinfo & info) {m_hthread = info. m_hthread; m_bbusyworking = info. m_bbusyworking ;}
Handle m_hthread;
Bool m_bbusyworking;
};
Typedef Map <DWORD, threadinfo> threadinfomap;
Typedef threadinfomap: iterator iterator_threadinfomap;
Enum threadpoolstatus {status_busy, status_idle, status_normal };
Public:
Cthreadpool ()
{
Initializecriticalsection (& m_cs );
}
Virtual ~ Cthreadpool ()
{
Deletecriticalsection (& m_cs );
}
Bool start (unsigned short nstatic, unsigned short Nmax)
{
If (Nmax <nstatic)
{
Assert (0 );
Return false;
}
Handle hthread;
DWORD nthreadid;
M_nnumberofstaticthreads = nstatic;
M_nnumberoftotalthreads = Nmax;
// Lock the resource
Entercriticalsection (& m_cs );
// Create an IO port
M_hmrioport = createiocompletionport (handle) invalid_handle_value, null, 0, 0 );
Hthread = createthread (
Null, // SD
0, // initial stack size
(Lpthread_start_routine) managerproc, // threadfunction
(Lpvoid) This, // thread argument
0, // creationoption
& Nthreadid); // thread identifier
M_hmgrthread = hthread;
// Now we start these worker threads
M_hworkerioport = createiocompletionport (handle) invalid_handle_value, null, 0, 0 );
For (long n = 0; n <nstatic; n ++)
{
Hthread = createthread (
Null, // SD
0, // initial stack size
(Lpthread_start_routine) workerproc, // threadfunction
(Lpvoid) This, // thread argument
0, // creation Option
& Nthreadid );
M_threadmap.insert (m_threadmap.end (), threadinfomap: value_type (nthreadid, threadinfo (hthread, false )));
}
Leavecriticalsection (& m_cs );
Return true;
}
Void stop (bool bhash = false)
{
Entercriticalsection (& m_cs );
: Postqueuedcompletionstatus (m_hmrioport, 0, 0, (overlapped *) 0 xffffff );
Waitforsingleobject (m_hmgrthread, infinite );
Closehandle (m_hmgrthread );
Closehandle (m_hmrioport );
// Shut down all the worker threads
Uint ncount = m_threadmap.size ();
Handle * pthread = new handle [ncount];
Long n = 0;
Threadinfo Info;
Iterator_threadinfomap I = m_threadmap.begin ();
While (I! = M_threadmap.end ())
{
: Postqueuedcompletionstatus (m_hworkerioport, 0, 0, (overlapped *) 0 xffffffff );
Info = I-> second;
Pthread [n ++] = info. m_hthread;
I ++;
}
DWORD rc = waitformultipleobjects (ncount, pthread, true, 30000); // wait for 0.5 minutes, then start to killthreads
Closehandle (m_hworkerioport );
If (rc> = wait_object_0 & rc <wait_object_0 + ncount)
{
For (unsigned int n = 0; n <ncount; n ++)
{
Closehandle (pthread [N]);
}
}
Else if (rc = wait_timeout & bhash)
{
// Some threadsnot terminated, we have to stop them.
DWORD exitcode;
For (unsigned int I = 0; I <ncount; I ++)
{
If (: getexitcodethread (pthread [I], & exitcode) = still_active)
{
Terminatethread (pthread [I], 99 );
}
Closehandle (pthread [I]);
}
}
Delete [] pthread;
Leavecriticalsection (& m_cs );
}
Void addtask (void * puser, itask * pworker) const
{
: Postqueuedcompletionstatus (m_hworkerioport ,\
Reinterpret_cast <DWORD> (pworker ),\
Reinterpret_cast <DWORD> (puser ),\
Null );
}
Protected:
Handle getmgrioport () const {return m_hmrioport ;}
Uint getmgrwaittime () const {return1000 ;}
Handle getworkerioport () const {return m_hworkerioport ;}
PRIVATE:
Static DWORD winapi workerproc (void * P)
{
// Convert the parameter to the server pointer.
Cthreadpool * pserver = (cthreadpool *) P;
Handle ioport = pserver-> getworkerioport ();
Unsigned long pn1, pn2;
Overlapped * poverlapped;
DWORD threadid =: getcurrentthreadid ();
While (: getqueuedcompletionstatus (ioport, & pn1, & pn2,
& Poverlapped, infinite ))
{
If (poverlapped = (overlapped *) 0 xfffffffe)
{
Pserver-> removethread (threadid );
Break;
}
Else if (poverlapped = (overlapped *) 0 xffffffff)
{
Break;
}
Else
{
Pserver-> setstatus (threadid, true );
// Retrieve the job description and Agent pointer
Itask * ptask = reinterpret_cast <itask *> (pn1 );
Void * puser = reinterpret_cast <void *> (pn2 );
Ptask-> processtask (puser );
Pserver-> setstatus (threadid, false );
}
}
Return 0;
}
Static DWORD winapi managerproc (void * P)
{
// Convert the parameter to the server pointer.
Cthreadpool * pserver = (cthreadpool *) P;
Handle ioport = pserver-> getmgrioport ();
Unsigned long pn1, pn2;
Overlapped * poverlapped;
Label_manager_processing:
While (: getqueuedcompletionstatus (ioport, & pn1, & pn2,
& Poverlapped, pserver-> getmgrwaittime ()))
{
If (poverlapped = (overlapped *) 0 xffffffff)
{
Return 0;
}
}
// Time Out Processing
If (: getlasterror () = wait_timeout)
{
// The manager will take a look at all the worker's status.
If (pserver-> getstatus () = status_busy)
Pserver-> addthreads ();
If (pserver-> getstatus () = status_idle)
Pserver-> removethreads ();
Goto label_manager_processing;
}
Return 0;
}
Protected:
// Manager thread
Handle m_hmgrthread;
Handle m_hmrioport;
Protected:
// Configuration parameters
Mutable unsigned short m_nnumberofstaticthreads;
Mutable unsigned short m_nnumberoftotalthreads;
Protected:
// Helper functions
Void cthreadpool: addthreads ()
{
Handle hthread;
DWORD nthreadid;
Unsigned int ncount = m_threadmap.size ();
Unsigned int ntotal = min (ncount + 2, m_nnumberoftotalthreads );
For (unsigned int I = 0; I <ntotal-ncount; I ++)
{
Hthread = createthread (
Null, // SD
0, // initial stack size
(Lpthread_start_routine) workerproc, // threadfunction
(Lpvoid) This, // thread argument
0, // creation Option
& Nthreadid );
M_threadmap.insert (m_threadmap.end (), threadinfomap: value_type (nthreadid, threadinfo (hthread, false )));
}
}
Void removethreads ()
{
Unsigned int ncount = m_threadmap.size ();
Unsigned int ntotal = max (nCount-2, m_nnumberofstaticthreads );
For (unsigned int I = 0; I <ncount-ntotal; I ++)
{
: Postqueuedcompletionstatus (m_hworkerioport, 0, 0, (overlapped *) 0 xfffffe );
}
}
Threadpoolstatus getstatus ()
{
Int ntotal = m_threadmap.size ();
Threadinfo Info;
Int ncount = 0;
Iterator_threadinfomap I = m_threadmap.begin ();
While (I! = M_threadmap.end ())
{
Info = I-> second;
If (info. m_bbusyworking = true) ncount ++;
I ++;
}
If (ncount/(1.0 * ntotal)> 0.8)
Return status_busy;
If (ncount/(1.0 * ntotal) <0.2)
Return status_idle;
Return status_normal;
}
Void setstatus (DWORD threadid, bool status)
{
Entercriticalsection (& m_cs );
Iterator_threadinfomap I;
Threadinfo Info;
I = m_threadmap.find (threadid );
Info = I-> second;
Info. m_bbusyworking = status;
M_threadmap.insert (m_threadmap.end (), threadinfomap: value_type (threadid, Info ));
Leavecriticalsection (& m_cs );
}
Void cthreadpool: removethread (dwordthreadid)
{
Entercriticalsection (& m_cs );
M_threadmap.erase (threadid );
Leavecriticalsection (& m_cs );
}
Protected:
// All the work threads
Threadinfomap m_threadmap;
Critical_section m_cs;
Handle m_hworkerioport;
};
//// // The original generation of the latest version //////////////// ////////////////////
Class ctest: Public itask
{
Public:
Ctest ()
{
Static int II = 0;
M_ii = II ++;
}
Void processtask (void * puser)
{
For (INT I = 0; I <3; I ++)
{
Cout <"taskid:" <(ctest *) puser)-> m_ii <Endl;
Sleep (100 );
}
}
~ Ctest ()
{
}
PRIVATE:
Int m_ii;
};
Int _ tmain (INT argc, _ tchar * argv [])
{
Cthreadpool * ppool = new cthreadpool ();
Const int test_count = 8;
Ctest test [test_count];
// Dynamic Route pool, with 5 processing routes and a maximum of 10 tasks
Ppool-> Start (5, 10 );
// Add tasks to the scheduler pool
For (INT I = 0; I <test_count; I ++)
Ppool-> addtask (& test [I], & test [I]);
Cin. Get ();
// Stop the Failover pool
Ppool-> stop ();
Return 0;
}