Developers under Windows know that asynchronous I / O is the secret of creating high performance and scalability applications. Because it allows a single thread to handle requests from different clients. This thread does not have to process these requests sequentially, nor does it have to be interrupted when waiting for the I / O request to run. For example, write network communication. Using the underlying Socket function Select can implement multiplexing. A server-side thread can listen to a port to respond to a request for multiple client processes. If it is a request to respond to a few customers, if it is a hundred thousand users, such as a server program for online games. Microsoft provides I / O Complete Port to resolve such a similar problem. So what do they do? They implemented a thread pool to handle the requests of those customers. Whenever the user requests the server, the server releases a thread response from the thread pool. The service end thread returns to the thread pool and hangs. Waiting for the next customer's request. There are many benefits of doing this, and you don't have to create a thread each time you create a request and release the thread after the request is completed. Save a lot of resources and reduce the inefficiency of the CPU's Context Switch. Let our programs have more so-called extensions, that is, the performance of the program increases with the improvement of the server's hardware configuration. (How tempting commitment! I have drooling.) At the same time, Microsoft also provides many thread pool functions for us to use. But Microsoft's consistent style is that developers only need to use it. There is no need to care about the internal implementation. This kind of behavior that makes developers as a fool even Win32 programmers cannot endure. As the topic of this article, I want to create a thread pool. I have completed this work for 39 degrees last Sunday, I seem to have more creativity than the body temperature.
In fact, the procedure in Windows, especially multi-threaded procedures is a very happy thing. Microsoft provides a powerful debugging tool to let us find bugs. How can developers under Windows how to live up to people's kindness.
There are many ways to implement a variety of thread pool: my idea is. Creating a loop queue each node contains CwinsRead pointers that use AFXBEGINTHREAD to create threads returned by Typedef struct threadnod
{
CWINTHREAD * pthread; // Pointer to Thread
Bool bidle; // if thread is idle
Threadnod * pnext; // Pointer to Next Node
} Threadnod;
CWINTHREAD is a thread class of Microsoft Package Our CWINAPP is derived from this class. In fact, AfxBeginThread can also create a GUI thread and enjoy a subsequent message queue. This is another interesting application. Because the thread pool is most efficient to have both the CPU twice the thread running at the same time, I created three threads. My CPU is 1. Creating 3 threads may be very difficult to understand. I am just to take care of my loop queue. If there are only two nodes in the queue (two threads) too much. If my machine is 2 CUP, I will create 4 threads without hesitation! When you have a request, I will take a thread response request from the thread pool. The thread is hanged after the end of the processing, waiting for the next request. Oh, I feel like it is a contractor! .
There is still the last question now how I know when the thread ends and hangs. I also launched a thread using WaitFormultiPleObjects () to monitor the state of the thread kernel object When the thread ends into a notification state. I will hang the thread. Wait a next time.
Uint WaitthreadState (LPVOID PPARAM)
{
Cthread * pthis = (cthread *) PPARAM;
DWORD DWWAIT = 0;
While (g_bflag)
{
dwweit = WaitFormultiplebjects (3,
PTHIS-> M_HEVENT,
False,
Infinite);
Switch (dwwait)
{
Case Wait_Object_0 0: // if Thread1 Finish Suspend IT
PTHIS-> m_pthread1-> suspendthread (); pthis-> node1-> bidle = true;
PTHIS-> m_pthreadnodehead = pthis-> node1;
Case Wait_Object_0 1: // if Thread2 Finish Suspend IT
PTHIS-> m_pthread2-> suspendthread ();
PTHIS-> NODE2-> BIDLE = TRUE;
PTHIS-> m_pthreadnodehead = pthis-> node2;
Case Wait_Object_0 2: // if Thread3 Finish Suspend IT
PTHIS-> m_pthread3-> suspendthread ();
PTHIS-> NODE3-> BIDLE = TRUE;
PTHIS-> m_pthreadnodehead = pthis-> node3;
}
}
Return 0;
}
The function CreateThreadPool is a creation of a thread pool and a list.
Bool cthread :: CreateThreadPool ()
{
m_pthread1 = :: afxbeginthread (thread1function,
(Lpvoid) this,
Thread_Priority_NORMAL,
0,
CREATE_SUSPENDED,
NULL);
m_pthread1-> m_bautodelete = false;
m_pthread2 = :: AfXBeginthread (thread2function,
(Lpvoid) this,
Thread_Priority_NORMAL,
0,
CREATE_SUSPENDED,
NULL);
m_pthread2-> m_bautodelete = false;
m_pthread3 = :: afxbeginthread (thread3function,
(Lpvoid) this,
Thread_Priority_NORMAL,
0,
CREATE_SUSPENDED,
NULL);
m_pthread3-> m_bautodelete = false;
m_pthread = :: afxbeginthread (waitthreadState,
(Lpvoid) this,
Thread_Priority_NORMAL,
0,
0,
NULL);
IF (! m_pthread ||! m_pthread2 ||! m_pthread1)
Return False;
m_hevent [0] = m_pthread1-> m_hthread;
m_hevent [1] = m_pthread2-> m_hthread;
m_hevent [2] = m_pthread3-> m_hthread;
Cthread :: node1 = new threadnod;
Node1-> pthread = m_pthread1;
Node1-> BIDLE = True;
Node1-> pnext = m_pthreadnodehead;
m_pthreadnodehead = node1;
Cthread :: node2 = new threadnod;
Node2-> pthread = m_pthread2;
Node2-> BIDLE = TRUE;
Node2-> pnext = m_pthreadnodehead;
m_pthreadnodehead = node2;
Cthread :: node3 = new threadnod; node3-> pthread = m_pthread3;
Node3-> BIDLE = true;
Node3-> pnext = m_pthreadnodehead;
m_pthreadnodehead = NODE3;
Node1-> pnext = m_pthreadnodehead;
Return True;
}
The GetThreadFromPool function is selected from the POOL to return to the corresponding thread pointer.
CWINTHREAD * CTHREAD :: GetThreadFromPool ()
{
INT nthreadcounter = 0;
IF (m_pthreadnodehead! = null)
{
ENTERCRITICALSECTION (& M_CS);
While (nthreadcounter! = 3)
{
IF-> BIDLE == True)
{
M_PthreadNodeHead-> bid = false;
LeavecriticalSection; & M_CS);
Return M_PthreadNodeHead-> Pthread;
}
M_PthreadNodeHead = m_pthreadnodehead-> pnext;
NTHREADCOUNTER ;
}
LeavecriticalSection; & M_CS);
}
Return NULL;
}
Get the thread pointer and call the previously hanging thread
Void Cthread :: Runthread (CWINTHREAD * PWINTHREAD)
{
IF (PWINTHREAD! = NULL)
{
PWINTHREAD-> ResumeThread ();
}
}