Reprint a C ++ thread pool code, which is very useful for favorites
# Ifndef _ ThreadPool_H _
# Define _ ThreadPool_H _
# Pragma warning (disable: 4530)
# Pragma warning (disable: 4786)
# Include <cassert>
# Include <vector>
# Include <queue>
# Include <windows. h>
Using namespace std;
Class ThreadJob // work base class
{
Public:
// Virtual functions called by the thread pool
Virtual void DoJob (void * pPara) = 0;
};
Class ThreadPool
{
Public:
// DwNum thread pool size
ThreadPool (DWORD dwNum = 4): _ lThreadNum (0), _ lRunningNum (0)
{
InitializeCriticalSection (& _ csThreadVector );
InitializeCriticalSection (& _ csWorkQueue );
_ EventComplete = CreateEvent (0, false, false, NULL );
_ EventEnd = CreateEvent (0, true, false, NULL );
_ SemaphoreCall = CreateSemaphore (0, 0, 0x7FFFFFFF, NULL );
_ SemaphoreDel = CreateSemaphore (0, 0, 0x7FFFFFFF, NULL );
Assert (_ SemaphoreCall! = INVALID_HANDLE_VALUE );
Assert (_ EventComplete! = INVALID_HANDLE_VALUE );
Assert (_ EventEnd! = INVALID_HANDLE_VALUE );
Assert (_ SemaphoreDel! = INVALID_HANDLE_VALUE );
AdjustSize (dwNum <= 0? 4: dwNum );
}
~ ThreadPool ()
{
DeleteCriticalSection (& _ csWorkQueue );
CloseHandle (_ EventEnd );
Closehandle (_ eventcomplete );
Closehandle (_ semaphorecall );
Closehandle (_ semaphoredel );
Vector <threaditem *>: iterator ITER;
For (iter = _ threadvector. Begin (); iter! = _ Threadvector. End (); ITER ++)
{
If (* ITER)
Delete * ITER;
}
Deletecriticalsection (& _ csthreadvector );
}
// Adjust the thread pool size
Int adjustsize (INT inum)
{
If (inum> 0)
{
Threaditem * pnew;
Entercriticalsection (& _ csthreadvector );
For (INT _ I = 0; _ I <inum; _ I ++)
{
_ Threadvector. push_back (pnew = new threaditem (this ));
Assert (pnew );
Pnew-> _ HANDLE = createthread (null, 0, defaultjobproc, pnew, 0, null );
// Set priority
Setthreadpriority (pnew-> _ HANDLE, thread_priority_below_normal );
Assert (pnew-> _ HANDLE );
}
Leavecriticalsection (& _ csthreadvector );
}
Else
{
INum * =-1;
ReleaseSemaphore (_ SemaphoreDel, iNum> _ lThreadNum? _ LThreadNum: iNum, NULL );
}
Return (int) _ lThreadNum;
}
// Call the thread pool
Void Call (void (* pFunc) (void *), void * pPara = NULL)
{
Assert (pFunc );
EnterCriticalSection (& _ csWorkQueue );
_ JobQueue. push (new JobItem (pFunc, pPara ));
LeaveCriticalSection (& _ csWorkQueue );
ReleaseSemaphore (_ SemaphoreCall, 1, NULL );
}
// Call the thread pool
Inline void Call (ThreadJob * p, void * pPara = NULL)
{
Call (CallProc, new CallProcPara (p, pPara ));
}
// End the thread pool and wait for synchronization
Bool EndAndWait (DWORD dwWaitTime = INFINITE)
{
SetEvent (_ EventEnd );
Return WaitForSingleObject (_ EventComplete, dwWaitTime) = WAIT_OBJECT_0;
}
// End Thread Pool
Inline void End ()
{
SetEvent (_ EventEnd );
}
Inline DWORD Size ()
{
Return (DWORD) _ lThreadNum;
}
Inline DWORD GetRunningSize ()
{
Return (DWORD) _ lRunningNum;
}
Bool IsRunning ()
{
Return _ lRunningNum> 0;
}
Protected:
// Working thread
Static dword winapi DefaultJobProc (LPVOID lpParameter = NULL)
{
ThreadItem * pThread = static_cast <ThreadItem *> (lpParameter );
Assert (pThread );
ThreadPool * pThreadPoolObj = pThread-> _ pThis;
Assert (pThreadPoolObj );
InterlockedIncrement (& pThreadPoolObj-> _ lThreadNum );
HANDLE hWaitHandle [3];
HWaitHandle [0] = pThreadPoolObj-> _ SemaphoreCall;
HWaitHandle [1] = pThreadPoolObj-> _ SemaphoreDel;
HWaitHandle [2] = pThreadPoolObj-> _ EventEnd;
JobItem * pJob;
Bool fHasJob;
For (;;)
{
DWORD wR = waitformultipleobjects (3, hwaithandle, false, infinite );
// Response to the deletion thread Signal
If (wR = wait_object_0 + 1)
Break;
// Obtain user jobs from the queue
Entercriticalsection (& pthreadpoolobj-> _ csworkqueue );
If (fhasjob =! Pthreadpoolobj-> _ jobqueue. Empty ())
{
Pjob = pthreadpoolobj-> _ jobqueue. Front ();
Pthreadpoolobj-> _ jobqueue. Pop ();
Assert (pjob );
}
Leavecriticalsection (& pthreadpoolobj-> _ csworkqueue );
// Determine whether to end the thread by receiving the end thread signal (end thread signal & whether there is work)
If (wR = wait_object_0 + 2 &&! Fhasjob)
Break;
If (fhasjob & pjob)
{
Interlockedincrement (& pthreadpoolobj-> _ lrunningnum );
Pthread-> _ dwlastbegintime = gettickcount ();
Pthread-> _ dwcount ++;
Pthread-> _ fisrunning = true;
Pjob-> _ pfunc (pjob-> _ ppara); // run the User Job
Delete pJob;
PThread-> _ fIsRunning = false;
InterlockedDecrement (& pThreadPoolObj-> _ lRunningNum );
}
}
// Delete its own structure
EnterCriticalSection (& pThreadPoolObj-> _ csThreadVector );
PThreadPoolObj-> _ ThreadVector. erase (find (pThreadPoolObj-> _ ThreadVector. begin (), pThreadPoolObj-> _ ThreadVector. end (), pThread ));
LeaveCriticalSection (& pThreadPoolObj-> _ csThreadVector );
Delete pThread;
InterlockedDecrement (& pThreadPoolObj-> _ lThreadNum );
If (! Pthreadpoolobj-> _ lthreadnum) // All threads end
Setevent (pthreadpoolobj-> _ eventcomplete );
Return 0;
}
// Call user object virtual functions
Static void callproc (void * ppara)
{
Callprocpara * CP = static_cast <callprocpara *> (ppara );
Assert (CP );
If (CP)
{
CP-> _ pobj-> dojob (CP-> _ ppara );
Delete CP;
}
}
// User object structure
Struct callprocpara
{
Threadjob * _ pobj; // user object
Void * _ ppara; // USER parameter
CallProcPara (ThreadJob * p, void * pPara): _ pObj (p), _ pPara (pPara ){};
};
// User Function Structure
Struct JobItem
{
Void (* _ pFunc) (void *); // Function
Void * _ pPara; // Parameter
JobItem (void (* pFunc) (void *) = NULL, void * pPara = NULL): _ pFunc (pFunc), _ pPara (pPara ){};
};
// Thread structure in the thread pool
Struct ThreadItem
{
HANDLE _ Handle; // thread HANDLE
ThreadPool * _ pThis; // thread pool pointer
DWORD _ dwLastBeginTime; // The last running start time
DWORD _ dwCount; // Number of running times
Bool _ fIsRunning;
Threaditem (threadpool * pthis): _ pthis (pthis), _ HANDLE (null), _ dwlastbegintime (0), _ dwcount (0), _ fisrunning (false ){};
~ Threaditem ()
{
If (_ HANDLE)
{
Closehandle (_ HANDLE );
_ HANDLE = NULL;
}
}
};
STD: queue <jobitem *> _ jobqueue; // work queue
STD: vector <threaditem *> _ threadvector; // thread data
Critical_section _ csthreadvector, _ csworkqueue; // work queue critical, thread data critical
Handle _ eventend, _ eventcomplete, _ semaphorecall, _ semaphoredel; // end notification, completion event, work signal, delete thread Signal
Long _ lThreadNum, _ lRunningNum; // Number of threads, number of running threads
};
# Endif // _ ThreadPool_H _
Basically, it is used and not familiar with WIN32 APIs, but still familiar with the logic of the thread pool. I think this thread pool is clearly written, I used it in a multi-threaded download module. Very practical.
Call Method
Void threadfunc (void * p)
{
YourClass * yourObject = (YourClass *) p;
//...
}
ThreadPool tp;
For (I = 0; I <100; I ++)
Tp. Call (threadfunc );
ThreadPool tp (20); // 20 indicates the size of the initial Thread Pool
Tp. Call (threadfunc, lpPara );
Notes:
1. ThreadJob is useless. Write the thread function directly.
2. the void * entry parameter of threadfunc can be converted to a custom type object. This object can record the data in the running thread and set the current state of the thread to interact with the thread.
3. The thread pool has an EndAndWait function to end all computing tasks in the thread pool. Sometimes a thread in the thread pool may take a long time to run. What should I do? It can be processed through the threadfunc entry parameter object, for example:
Class YourClass {
Int cmd; // cmd = 1 indicates that the upper thread stops computing and Exits normally.
};
Threadfunc (void * p ){
YourClass * yourObject = (YourClass *) p;
While (true ){
// Do some calculation
If (yourClass-> cmd = 1)
Break;
}
}
Set yourClass-> cmd = 1 in the main thread, and the thread ends naturally.
Simple and common thread pool implementation.
If you need to stop the call, you can add a control variable to the input thread function parameters,
Class YourClass {
Int cmd; // cmd = 1 indicates that the upper thread stops computing and Exits normally.
};
Threadfunc (void * p ){
YourClass * yourObject = (YourClass *) p;
While (true ){
// Do some calculation
If (yourClass-> cmd = 1)
Break;
}
}
In threadFunc, the processing you do is not in a while loop, but a complicated painting process. You may need to set several control points during the painting process, determine whether yourClass-> cmd is 1 to terminate the thread.
Of course, using TerminateThread may be a solution, but do not use it because of memory and other problems.
I think what you do is data transmission. If you use C/C ++ to write a plotting program, you do not need to write multiple painting threads.