Multithreading in Windows
A thread is a separate path of execution within a program. Windows is a preemptive multithreading operating system which manages threads. Each program is assigned a single thread of execution by default.
Multithreading has many benefits in windows applications, such as:
· Each child window in an MDI application can be assigned to a different thread.
· If the drawing part (OnDraw code) of the program takes a long time to execute, the GUI will be blocked until the redraw is completed. However, we can assign a separate thread to the OnDraw function, thus causing the application to be responsive when long redraws occur.
· Multiple threads can be concurrently executed if there are multiple CPUs in the system thus speeding up the execution of the program.
· Complex simulations can be carried out efficiently by assigning a separate thread to each simulation entity.
· Important events can be handled efficiently by assigning those to a high priority thread.
Note that each thread can be in one of three possible states, i.e., it could be in running state where it has the attention of the CPU, or it could be blocked if it is waiting on a resource, or it could be in ready state residing in a priority queue. In a multi-processor computer, many threads can be in the running state depending upon the number of CPUs.

The operating system is continuously managing threads, moving them from running to blocked, or ready state, then picking the next ready thread to give to the CPU and changing its state to running. If the time slice (typically one millisecond) for a thread expires while it is in the running state, it is moved to the ready queue. If, however, the thread needs to wait on a resource (such as I/O, or some data arrival) before its time slice expires, it is moved to the blocked queue, where it will reside until the resource becomes available.
In windows, each process is assigned a single thread of execution by default. Each thread gets its own stack space but shares the heap space and the global variables with other threads in the process as shown below.


A
Process with One Thread
A Process with
Three Threads
The Windows operating system provides a CreateThread API function which you can call to start a thread function. Its prototype looks like.
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES pSecurityAttributes,
DWORD stackSize,
LPTHREAD_START_ROUTINE pStartAddr,
LPVOID pThreadParm,
DWORD createFlags,
LPDWORD pThreadID)
As you can see from the above prototype, the CreateThread function starts a function as a new thread (indicated by the LPTHREAD_START_ROUTINE parameter) and passes a single LPVOID type parameter to this function. The windows API provides extensive set of functions for thread creation, destruction, synchronization and signaling. However using the MFC library to create and manage threads makes it much easier as there is a single class called “CWinThread" that you need to learn.
MFC Threads:
MFC has two kinds of threads, worker threads and user interface threads. Majority of the time, we create worker threads to divide the computation into different threads. MFC provides two global functions AfxBeginThread and AfxEndThread to create and terminate threads. A thread is written as a simple function that takes one parameter of LPVOID type and has a UINT return type. AfxBeginThread calls this function and has the thread function name and the parameter to be given to the thread function as its parameters. AfxBeginThread creates one object of the CWinThread class on the heap and returns a pointer to it. CWinThread holds a handle to the created thread through its m_hThread data member. It is through this CWinThread object that we can control the thread priority and its termination etc.. Note that AfxBeginThread calls the CreateThread API function to create a thread.
Example: Create an SDI application called SDIThread. Add a simple function called MyBeep which will beep every two seconds. Invoke the thread through the OnInitialUpdate function that you can write by first going through the class wizard.
//-----------Thread
function----------------
UINT
MyBeep(LPVOID pParam)
{
while(1) {
Beep(100,100);
Sleep(2000); //
block for 2 seconds
}
return 0;
}
void
CSDIThreadView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized
code here and/or call the base class
AfxBeginThread(MyBeep,NULL);
}
Build and test the program. You can download the executable and test it on your machine by clicking on this link: Executable for SDIThread. After clicking, you can either choose the program to be saved on your computer or open it from its current location.
You can modify the code to pass the interval parameter as shown below.
//-----------Thread
function----------------
UINT
MyBeep(LPVOID pParam)
{
int * duration = (int *)
(pParam); // need to type cast it as pParam is LPVOID
while(1) {
Beep(600,500); // frequency, duration
Sleep(*duration);
// block for 2 seconds
}
return 0;
}
int
interval;
void
CSDIThreadView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized
code here and/or call the base class
interval = 2000;
AfxBeginThread(MyBeep,&interval);
}
Thread Termination:
A thread can terminate in one of three ways.
1. The thread functions ends.
2. The program calls AfxEndThread.
3. The application terminates.
In the first two scenarios, the destructor for the CWinThread object is called and so there are no memory leaks (recall that the CWinThread object is created on the heap by the AfxBeginThread function). However, in the third scenario, the program will have memory leaks as the CWinThread object is not deleted from the stack. Thus in our previous example where the thread function “MyBeep()” is running in an infinite loop, there is a memory leak when the program is terminated.
One possibility is to provide a loop variable in the thread function which may terminate the function when the program is ending. Modify the thread function to as shown below. You will need to write the WM_DESTROY handler in the view class by using the class wizard.
int interval;
// global
BOOL b_terminate = FALSE;
// global
CWinThread * pThread;
// global
//-----------Thread function----------------
UINT MyBeep(LPVOID pParam)
{
int * duration = (int *) (pParam);
while(!b_terminate) {
Beep(1000,1000); // frequency, duration
Sleep(*duration); // block for duration miliseconds
}
return 0;
}
void CSDIThreadView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
interval = 2000;
pThread =
AfxBeginThread(MyBeep,&interval);
}
void CSDIThreadView::OnDestroy()
{
CView::OnDestroy();
// TODO: Add your message handler code here
b_terminate = TRUE;
}
Now as you can see that when the program is terminated, WM_DESTROY handler sets b_terminate to true which can then potentially terminate the MyBeep thread function. However, this program will still have memory leaks in the case when the main thread gets done before the MyBeep thread. To solve this problem, the only solution that is guaranteed to work is to have the main program wait for the thread to finish in the WM_DESTROY handler. Modify the code to as shown below.
int interval;
// global
BOOL b_terminate = FALSE;
// global
//-----------Thread function----------------
UINT MyBeep(LPVOID pParam)
{
int * duration = (int *) (pParam);
while(!b_terminate) {
Beep(1000,1000); // frequency, duration
Sleep(*duration); // block for duration miliseconds
}
return 0;
}
void CSDIThreadView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
interval = 2000;
pThread =
AfxBeginThread(MyBeep,&interval);
pThread->m_bAutoDelete = FALSE; //
CWinThread object will not be destroyed
}
// automatically if thread function ends
void CSDIThreadView::OnDestroy()
{
CView::OnDestroy();
// TODO: Add your message handler code here
b_terminate = TRUE;
WaitForSingleObject(pThread->m_hThread,INFINITE); //
wait for thread to terminate
delete pThread;
}
The above code is very typical of those situations where the thread function runs in a long loop, and the main thread needs to wait on the thread function to finish first, so that there are no memory leaks.
Thread Priorities:
Each thread in Windows can be given a priority from 1 to 31 (with 31 being the highest priority). The application is given a priority class when it is started. Here is a list of the different priority classes:
Class Base Priority
IDLE_PRIORITY_CLASS 4
NORMAL_PRIORITY_CLASS foreground: 9 background: 7
HIGH_PRIORITY_CLASS 13
REALTIME_PRIORITY_CLASS 24
By calling the CWinThread member function “SetThreadPriority”, you can change the priority of a thread within its class. The SetThreadPriority takes one of the following values.
THREAD_PRIORITY_LOWEST -2 (subtracts 2 from current priority)
THREAD_PRIORITY_BELOW_NORMAL -1
THREAD_PRIORITY_NORMAL 0
THREAD_PRIORITY_ABOVE_NORMAL +1
THREAD_PRIORITY_HIGHEST +2
For example, if a foreground thread’s priority is changed by calling:
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL), then its priority will become 8 (i.e., 9-1).
One of the important rules to remember is not to assign a continuously running thread function a high priority. This is because when its time slice expires and it goes back to the ready queue, it will be picked again by the OS scheduler as its priority is higher than other threads. Only occasionally the random scheduling built into the scheduler may pick another thread.
The CWinThread class also has member functions to suspend or resume a thread.
Example: Create an MDI application called dots2.
Add the following code to the view class header file:
// Attributes
public:
CDots2Doc* GetDocument();
BOOL bKill;
CWinThread * pThread1;
CWinThread * pThread2;
Add the following code (OnInitialUpdate, WM_DESTROY handlers and two thread functions) to the dots2view.cpp file. Note that the first thread function draws a blue dot randomly in the client area while the second thread function draws a red dot. Also note that the OnInitialUpdate function, sets the priority of the second thread (red thread) to two less than the normal priority.
void
CDots2View::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
bKill = FALSE;
AfxMessageBox(" On initial update called ");
pThread1 = AfxBeginThread(DotThread1, this);
pThread1 -> m_bAutoDelete = FALSE;
pThread2 = AfxBeginThread(DotThread2, this);
pThread2 -> m_bAutoDelete = FALSE;
pThread2->SetThreadPriority(THREAD_PRIORITY_LOWEST);
}
void
CDots2View::OnDestroy()
{
CView::OnDestroy();
// TODO: Add your message handler code here
bKill = TRUE;
WaitForSingleObject(pThread1->m_hThread, INFINITE);
delete pThread1;
WaitForSingleObject(pThread2->m_hThread, INFINITE);
delete pThread2;
}
// Thread 1 function
UINT DotThread1 (LPVOID
pParam)
{
CDots2View * view = (CDots2View *) pParam;
CRect r;
srand(GetTickCount());
while (!view->bKill)
{
CClientDC dc(view);
view->GetClientRect(&r);
int i = rand() % r.Width();
int j = rand() % r.Height();
dc.SetPixel(i,j,RGB(0,0,255));
}
return 0;
}
// Thread 2 function
UINT DotThread2 (LPVOID
pParam)
{
CDots2View * view = (CDots2View *) pParam;
CRect r;
srand(GetTickCount());
while (!view->bKill)
{
CClientDC dc(view);
view->GetClientRect(&r);
int i = rand() % r.Width();
int j = rand() % r.Height();
dc.SetPixel(i,j,RGB(255,0,0));
}
return 0;
}
In the IDR_DOTS2TYPE menu resource, add a menu item called Thread. Underneath it, create two menu items, Suspend 1, and Resume 1 (which will allow us to either suspend or resume the first thread).
In the dots2view.cpp file, add the code for the Suspend 1 (ID_THREAD_SUSPEND1) and Resume 1 (ID_THREAD_RESUME1) menu handlers.
void
CDots2View::OnThreadSuspend1()
{
// TODO: Add your command handler code here
int m = pThread1->SuspendThread();
CString s1;
s1.Format(" count = %d",m);
AfxMessageBox(s1);
}
void
CDots2View::OnThreadResume1()
{
// TODO: Add your command handler code here
pThread1->ResumeThread();
}
Build and execute the program. Experiment with suspending and resuming the first thread. You will notice that in the beginning, the client area is filled with blue dots as its thread has a higher priority. However, as you suspend the first thread, the client area starts to fill with red dots.

You can try the executable for the above program by clicking on the following hyperlink. Executable for the Dots2 program. After starting the program, you will notice that majority of the time, the blue thread executes because it has a higher priority. Only once in a while the thread scheduler gives the red thread a chance to execute. You can try suspending the BlueThread by selecting "Suspend 1" from the Threads menu to see that now the red thread is getting the CPU time more frequently.
As mentioned earlier, when there is a significant amount of drawing code (from execution time point of view) in the client area, the user interface is blocked out when the drawing is taking place. However, the application can be made more responsive by running the drawing code in a separate thread from the main thread.
Example:
Create another MDI application called mandel. This will do a fractal image drawing (which can be time consuming if the area is large).
Type the following code in the mandelview.h file. (It has some extra code related to a dll that I wanted to show later when discussing creation of dlls).
UINT mydraw(LPVOID
pParam);
typedef UINT
(DRAWIT)(LPVOID pParam);
extern "C"
__declspec(dllimport) UINT drawitdll(LPVOID pParam);
struct dllparam {
//
CClientDC *pdc;
HDC * pDC;
CRect r1;
};
//------- provideed by the
testdll.dll now
const int
NUM_ITERATIONS=64;
const double left =
-1.5;
const double right =
1.25;
const double top =
-1.25;
const double bottom =
1.25;
typedef struct
{
double real;
double imag;
} complex;
UINT drawit(LPVOID
pParam);
void Initcolors();
class CMandelView : public
CView
{
protected: // create from
serialization only
CMandelView();
DECLARE_DYNCREATE(CMandelView)
// Attributes
public:
CMandelDoc* GetDocument();
CWinThread * pmythread;
DRAWIT * pFunction; // used in the dll version
…..
…..
Type the following code (some are event handlers that you will need to add through the class wizard) in the mandleview.cpp file. Add a menu item called “Draw” under the window menu. Also add a menu called Drawing Thread. Underneath it, add suspend and resume menu items.
DRAWIT * pF;
// -------- these are
provided by the testdll.dll --
DWORD colors[64];
void Initcolors()
{
// TODO: add construction code here
WORD x;
BYTE red=0, green=0, blue=0;
for (x = 0; x < 64; x++)
{
colors[x] = RGB(red, green, blue);
if (!(red+= 64))
if (!(green+= 64))
blue += 64;
}
colors[63] = RGB(255,255,255);
}
CMandelView::CMandelView()
{
// TODO: add construction code here
::Initcolors();// now dll is going to do this
/*
HINSTANCE hInstance; // load a DLL
VERIFY (hInstance =
::LoadLibrary("c:\\windows\\system\\testdll.dll"));
VERIFY (pFunction =
(DRAWIT*)::GetProcAddress(hInstance,"drawitdll"));
pF = pFunction;
AfxMessageBox("dll loaded"); */
}
void
CMandelView::OnInitialUpdate()
{
//
CView::OnInitialUpdate();
// TODO: Add your specialized code here and/or call the base class
}
void
CMandelView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
// TODO: Add your specialized code here and/or call the base class
CClientDC dc(this);
CRect r;
GetClientRect(&r);
dllparam d1;
d1.pDC = &(dc.m_hDC);
d1.r1 = r;
//
(*pF)(&d1);
//
pmythread = AfxBeginThread(drawit,this);
::drawit(this);
//drawing without a thread, uncomment to see its effect
//
pmythread = AfxBeginThread(pF,&d1);
}
UINT mydraw(LPVOID
pParam)
{
dllparam * d1 = (dllparam *) pParam;
(*pF)(d1);
return 0;
}
UINT drawit(LPVOID pParam)
{
CRect r;
double xstep, ystep;
double x, y;
int i, j;
WORD iter;
complex k;
complex z;
double real, imag, spread;
CView * pview = (CView *) pParam;
CClientDC dc(pview)