Concurrency and Synchronization

Страницы работы

Содержание работы

Threads--Concurrency and Synchronization

What is a
thread? It’s a piece
of executable code which is given its own time slice by the operating system.

A process owns
at least one thread, and also owns memory space. A thread shares the memory
space of the process that owns it. Every thread is owned by some process.

Usually, your
program’s main thread manages the user interface, and any other threads manage
computational tasks.

The class CWinThread
wraps the Win32 thread object. As usual with MFC wrapper classes, in
addition to creating the C++ object, you must call the thread’s Create
function to create the associated Win32 thread. Sometimes one hears
"application thread" and "system thread". These are other
terms for CWinThread objects and Win32 threads.

Every thread has a
function (known as a “thread procedure”) which specifies its task. There are
two kinds of threads: interface threads, and worker threads. In an interface
thread, the thread procedure has a message loop, so it processes Windows
messages, while the thread procedure of a worker thread does not. You cannot
send a Windows message to a worker thread.

When we speak of a
“message loop”, we mean something like the code we discussed at the beginning
of the semester. Roughly,

while(msg = GetMessage())

{ DispatchMessage(msg);

}

Possible States
of a Thread

Ready. Waiting for the CPU to give it a time
slice so it can execute code.

Running. Using the CPU right now.

Blocked. Waiting for input.

Terminated. Has finished, by executing a return or
exit statement, or throwing an unhandled exception.

Scheduler

This is a
component of the operating system that switches the states of threads.

Interthread
Communication

Since all threads
owned by a process have access to the memory owned by that process, they can
communicate by writing to and reading from that memory. They can treat it as
a “bulletin board”.

One can also
communicate with an interface thread by sending it a Windows message. This
can be done using the SendMessage or PostMessage functions, which
in MFC appear as member functions in the CWnd class. You cannot
communicate with a worker thread in this way, since its Run does not
have a message loop.

Kruglinksi's
Example Program

1. Make an SDI
application, accepting all defaults. I called mine ThreadTest.

2. Insert a new
dialog, with ID number IDD_COMPUTE, change the OK button to Start (ID_START),
and add a progress bar:

The point of the
example: when you press Start, some long computation will begin in a worker
thread, and its progress will be shown on the progress bar, and you can
interrupt it with the Cancel button at any time.

3. Use Class
Wizard to add a class CComputeDlg corresponding to this dialog. Add to
this class, button handlers OnStart and OnCancel.

4. Add global
variables (integers) g_nCount and g_nMaxCount,

and initialize
them in the constructor of CComputeDlg to 0 and 10000, respectively.
Add a member variable m_nTimer of type int.

5. Add OnLButtonDown
to the view class, and make it bring up the dialog:

void CThreadTestView::OnLButtonDown(UINT nFlags,
CPoint point)

{

CComputeDlg dlg;

dlg.DoModal();

}

Of course you will
have to add #include "ComputeDlg.h" in your view class .cpp
file before you can compile this. If you like you can add

pDC->TextOut(5,5,"Press
the left mouse button here.") in OnDraw. Now the dialog will come up when you click the
mouse.

6. Map the
WM_TIMER message in CComputeDlg:

void CComputeDlg::OnTimer(UINT nIDEvent)

{ CProgressCtrl *pBar =

( CProgressCtrl
*)GetDlgItem(IDC_PROGRESS1);

pBar->SetPos(g_nCount *100/ g_nMaxCount);

}

The variable g_nCount
is going to measure the progress. The position needs to be set in percentages,
so it has to be scaled. The thread is going to run until g_nCount == g_nMaxCount.

6.
What do we want the
worker thread to do? We just make up something that will take up time. Just
let the computer count to ten thousand, ten thousand times. After each count
to ten thousand, it increments g_nCount. When it finishes, it posts a
message to the main thread. That message is a user-defined message (explained
below). The following code will be executed by the worker thread. In this
approach, this code is a global function, not belonging to any class. You can
put it in the CompDlg.cpp file, for example.