How To Multithread an Application
Author: David Nishimoto
email: davepamn@relia.net
Download
Overview: The articles explains:
- Why threads are used in applications
- How to create a thread.
- Three different techniques for synchronizing a thread
- How to suspend and resume a thread execution
- What the different thread priorities mean
- How to terminate a thread.
Threads
Attributes
ClientId
Context
Dynamic Priority
Base Priority
Processor Affinity
Excutiontime
Alert Status
Suspension count
Impersation token
Termination port
Exit Status
Methods
Create Thread
Open Thread
Query thread Information
Set thread Information
Current Thread
Terminate Thread
Get context
Set context
Suspend
Resume
Alert
Test Alert
Register termination port
Concept 1:
When a program wants to do several things at once, it creates threads.
This allows the program to be two places at once. The system keeps
track of the number of threads, and gives each a slice of the cpu.
Concept 2:
Every Process has a primary thread. All threads belonging to the process
share the assets of the process: global variables, the processes private space memory, and
file and com objects.
SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL);
Getting the Primary thread is accomplished by using the GetCurrentThread api. The primary
thread's priority is set above normal so the application does not appear sluggish during
user interface.
Concept 3:
Any thread can create other threads. Threads run independant of other threads.
Threads make the application appear more responsive to the user.
Concept 4:
When a thread is created a thread handle is returned. During thread initialization the
thread Callback function is set, in this case, StartThread1. Each thread function
can receive a LPVOID argument, in this case, a pointer to the CMultithreadView2 class
is sent.
m_threadlist[iCount].hThread = CreateThread( NULL, 0,
(LPTHREAD_START_ROUTINE)StartThread1,
(LPVOID)(this),
CREATE_SUSPENDED,
(LPDWORD)(&(m_threadlist[iCount].dwThreadID)) );
The CreateThread api initializes m_threadlist[iCount].dwThreadID with the threadId. You will need
both the Thread Object and Thread Id to control the thread.
A thread can be closed with the CloseHandle api. The system will not destroy a running thread
even though its handle has been closed. The system removes a thread after all its handles have
been closed.
Use
ExitThread(ERROR_CODE);
to gracefully exit a thread function, such as, StartThread1.
for(i=0; i
{
wRC=TerminateThread(m_threadlist[i].hThread,0);
CloseHandle(m_threadlist[i].hThread);
}
TerminateThread will not allow the thread to complete is execution path.
Threads can not protect against termination.
Concept 5:
A thread can be suspending and resumed.
Suspense:
for( iCount=0; iCount
{
SuspendThread( m_threadlist[iCount].hThread);
}
Resume:
for( iCount=0; iCount
{
SuspendThread( m_threadlist[iCount].hThread);
}
Concept 6:
Threads can be synchronized.
1. A Mutex is created.
2. A Mutex protects a section of code from use from
another thread while the current thread is executing.
3. Once the thread has executed the critical path
the Mutex is release for another process to gain
access to the critical path.
hDrawMutex = CreateMutex( NULL, FALSE, NULL );
Using a Mutex
See StartThread1:
dwWait = WaitForSingleObject( hDrawMutex, INFINITE );
if( dwWait == 0 )
oThreadView->Addition();
ReleaseMutex( hDrawMutex );
Using an Single Event:
1. The Thread waits until the hStartFactorEvent is signal
2. The Thread executes through the critical code
3. The hStartFactorEvent is reset
dwWait = WaitForSingleObject( hStartFactorialEvent, INFINITE );
if( dwWait == 0 )
{
oThreadView->Factorial();
}
ResetEvent(hStartFactorialEvent);
Using Multiple Events:
1. The hDependantSignals is an array of two events
2. Both events must be signalled before the thread
can proceed through the critical code.
dwWait = WaitForMultipleObjects( 2, hDependantSignals, TRUE, 0 );
if( dwWait == 0 )
{
oThreadView->Prime();
}
ResetEvent(hDependantSignals[0]);
ResetEvent(hDependantSignals[1]);
Signaling Thread active by Events
1. Every 2000 clicks the Factoral thread will be signalled
2. Every 500 clicks the prime number generated will be signalled.
The signal in this case originate in one location, but it could be
generated from multiple threads. Significantly, thread A completes
a phase of code and sends a signal and thread B completes a phase of
code and sends a signal. Both signals are received by the
factorial thread and execution of the critical code section commences.
void CMultithread2View::OnTimer(UINT nIDEvent)
{
DWORD dwClicks;
static DWORD dwOldClicks=GetTickCount();
static DWORD dwOldClicks2=GetTickCount();
dwClicks=GetTickCount();
if ((dwClicks-dwOldClicks)>2000)
{
SetEvent(hStartFactorialEvent);
dwOldClicks=dwClicks;
}
//Start Prime Generator
if ((dwClicks-dwOldClicks2)>500)
{
SetEvent(hDependantSignals[0]);
SetEvent(hDependantSignals[1]);
dwOldClicks2=dwClicks;
}
// TODO: Add your message handler code here and/or call default
UpdateData(FALSE);
CFormView::OnTimer(nIDEvent);
}
Concept 7:
Threads can protect critical sections of code from other threads.
Both Mutexes and critical section only allow one process
access at a time.
void InitializeCriticalSection(LPCRITICAL_SECTION lpcs);
void EnterCritericalSectoin(LPCRITICAL_SECTION lpcs);
void LeaveCriticalSection(LPCRITICAL_SECTION lpcs);
void DeleteCriticalSection(LPCRITICAL_SECTION lpcs);
|