Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Microsoft Visual C++ .NET Professional Projects - Premier Press

.pdf
Скачиваний:
168
Добавлен:
24.05.2014
Размер:
25.78 Mб
Скачать

130

Part I

 

INTRODUCING VC++.NET

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The execution of the application begins with creation of an object of your appli-

 

 

cation class. Following this, the control passes on to the InitInstance function of

 

 

the application class. Here the document template is created and registered. If

 

 

there are no command-line parameters, the ProcessShellCommand function

 

 

invokes the OnFileNew function, which further invokes the OnNewDocument

 

 

function of the document class. If any file name is specified on the command line,

 

 

then the ProcessShellCommand function invokes the OnFileOpen function, which

 

 

then invokes the OnOpenDocument function of the document class. The control

 

 

then returns to the ProcessShellCommand, which then constructs the view and

 

 

attaches it to the document.

 

Y

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The application then enters into the message loop that is encapsulated in the Run

 

 

member function of the CWinApp class.LThe message routing is handled by the

 

 

OnCmdMsg member function of the CCmdTargetFclass, which is the base class for all

 

 

objects that can handle messages. Figure 5-7 depicts the message routing as han-

 

 

dled by the framework.

 

M

 

 

 

 

 

 

 

 

 

 

 

A

 

 

 

 

 

 

 

 

 

 

passedE

 

passed

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Application's

 

on to

 

Application

 

on to

Main frame

 

 

message queue

 

T

object

 

 

 

window object

 

 

 

 

 

 

 

 

 

 

 

passed

 

 

 

on to

 

 

Is there any

passed

no

 

on to

 

message

 

 

View class

 

 

handler?

 

passed

 

 

If yes, then the view class

on to

 

 

 

 

handles the message.

 

 

 

 

passed

 

all unprocessed

Document

on to

Frame

messages, passed on to

class

 

window

Application class

FIGURE 5-7 Message routing in a Document/View-based application

Team-Fly®

THE DOCUMENT/VIEW ARCHITECTURE

Chapter 5

131

 

 

 

Summary

You’ve just gone through a fairly robust architecture offered by the MFC — the Document/View architecture. This architecture comes in handy for creating truly robust applications, which would otherwise be a tough and time-consuming task. It also gives you enough flexibility by allowing you to either stay with the given framework and create applications by tailoring it to the minimal, or edit and expand the framework to provide the required functionalities to the application. However, remember that not all applications have to be based on the Document/View architecture. Mostly, applications that have to deal with a lot of data and simultaneously interact with the user are designed using the Document/View architecture. It is the most apt choice because the architecture clearly demarcates data handling from data presentation and thus eases the task of handling both voluminous data and the presentation of data in various formats. If you are not designing such data-centric applications, you can choose to stick to applications that are not based on the Document/View architecture.

This page intentionally left blank

Chapter 6

Threads

In Chapter 5, you learned about the components of the Document/View architecture and also learned to create document-centric applications. In this chapter, you will learn about threads. This chapter discusses the basic concepts of threads and also

covers the procedure for creating single and multithreaded applications.

Basics of Threads

Before discussing threads, you need to learn about a related concept — processes. The operating system treats each executing instance of an application as a process, and each process has its independent system resources, such as memory and CPU timings. For instance, when you start Microsoft Word, Windows creates a corresponding process and allocates the required resources for the process. Also, operating systems, such as Windows 95 and higher versions of Windows, can support multiple processes running simultaneously. For example, you start Microsoft Word and Microsoft Excel. This results in creation of two processes.

Now you know what are processes. However, still you have a question unanswered. How are processes related to threads? Well, whenever a process is initiated, internally a thread is created that starts executing the application. In simple words, a thread is a path for execution within a process and can be defined as the smallest unit of executable code. Additionally, a thread by itself cannot request for any resources. As a result, it utilizes the resources that are allocated to the process of which the thread is a part.

As stated earlier, along with each instance of an application, a process is initiated, and each of these processes is in turn associated with at least a single thread. Thus, an application is always associated with a thread that is referred to as the primary thread. The primary thread consists of the startup code of an application and the address of the main or WinMain function of the application. When an application starts, the primary thread of the application is supplied to the operating system. If you terminate the primary thread of the application, the startup function, main or WinMain, also terminates and hence results in the termination of the related application.

You can create two types of threaded applications, single-threaded and multithreaded applications. These are discussed in detail next.

THREADS

Chapter 6

 

135

 

 

 

 

 

Single-Threaded Applications

An application that consists of only the primary thread is known as a singlethreaded application. In this type of application, a single thread handles the entire processing of the application, and hence all the tasks are handled in a sequence. Therefore, each task needs to wait until the previous task gets over.

Single-threaded applications are ideal for situations where you need to perform different tasks in a linear fashion, and do not require parallel processing for any task. Consider a situation in which you need to create an application that has to accept user input and store it in the hard disk. Here, you need to perform the two tasks sequentially. You need to accept data from the user, and then save the data on the hard disk. Obviously, you cannot store data before accepting it from the user. In such a situation, single-threaded applications come in handy.

Multithreaded Applications

Based on your experience, you know that very often your application has to handle multiple tasks simultaneously. So, how will your applications cater to such requirements? All you need to do is to create multithreaded applications. To understand the need for multithreaded applications better, consider a situation in which you need to create a gaming application for a car race. This application involves six cars that start from the starting point and compete until the finish line.

The first aspect to examine is how a single-threaded application works in this scenario. To begin with, out of the six cars, one starts from the start line and moves until it reaches the finish line. Next, the second car starts and reaches the finish line. This sequence continues until all six cars reach the finish line. The problem is pretty much obvious! Unless all six cars move together, you cannot categorize this as a race application. Such scenarios can be dealt with easily by designing multithreaded applications.

Any application that supports more that one thread is known as a multithreaded application. In a multithreaded application, you can handle multiple tasks simultaneously. Continuing with the example of the race application, you can create an individual thread for each car, and these threads can be executed parallel to each other. This means that the six cars in the race run independent of each other, and the application provides you the desired results.

Usually, you create additional threads to handle any background processing or other maintenance tasks. Some classic cases that can be implemented using

136

 

Part I

 

INTRODUCING VC++.NET

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

multiple threads are printing a document that is currently being edited by the user,

 

 

 

 

and recalculating spreadsheet entries as soon as the user updates a cell. Thus, cre-

 

 

 

 

 

 

ating multiple threads in an appli-

 

 

 

 

 

 

 

 

 

MULTITASKING

 

 

 

cation not only enhances its

 

 

 

 

 

 

 

 

 

 

Multitasking is the process of simultaneous-

efficiency

but

also

enables it to

 

 

 

 

optimize its utilization of resources.

 

 

 

 

ly executing more than one task. An appli-

 

 

 

 

cation can handle pure multitasking

Hitherto,

we

had

categorized

 

 

 

 

processes only if the application is running

 

 

 

 

applications based on the number

 

 

 

 

in a multiprocessor environment. In a sin-

 

 

 

 

of threads they worked with.

 

 

 

 

gle-processor environment, a Windows

 

 

 

 

application simulates the multitasking

Besides supporting these types of

 

 

 

 

process by using time slicing. Time slicing is

applications, MFC

also supports

 

 

 

 

the concept of dividing the CPU time

two types of threads: user-interface

 

 

 

 

between different processes. Each process

 

 

 

 

threads and worker threads. What

 

 

 

 

is given a CPU time slice in a round-robin

 

 

 

 

follows is

a

detailed discussion

 

 

 

 

fashion. In this method, while a process is

 

 

 

 

about these types of threads.

 

 

 

 

allocated the CPU’s time slice, other

 

 

 

 

processes wait for their turn. Time slicing

 

 

 

 

 

 

 

 

does not stop at the process level; it is

User-Interface Threads

 

 

 

 

implemented at the thread level, too, and

 

 

 

 

 

 

 

 

 

 

 

 

because the time slice for each thread is of

The thread that handles the user

 

 

 

 

the order of milliseconds, multiple tasks of

input is known as the user-interface

 

 

 

 

an application appear to be running parallel

thread. In most cases, an applica-

 

 

 

 

to each other. However, in a multiprocessor

 

 

 

 

tion has only

one

user-interface

 

 

 

 

environment, you can execute each thread

 

 

 

 

thread. This thread handles all the

 

 

 

 

on a separate processor and have all the

 

 

 

 

threads running parallel to each other.

events that are generated as a

 

 

 

 

Figure 6-1 displays the process of multitask-

response to different user activities,

 

 

 

 

 

 

 

 

 

 

Application

Threads

Process A

Process B

FIGURE 6-1 The process of multitasking

THREADS

Chapter 6

 

137

 

 

 

 

 

such as a key press or a mouse click, and the windows messages. The MFC class that offers all functionalities of threads is the CWinThread class. Also, in the hierarchy of the MFC classes, the CWinThread class is the base class for the CWinApp class. Thereby, the CWinApp class inherits all thread-processing functionalities from its base class. As a result, one of the classic examples for a user-interface thread is the application object, which is an instance of the CWinApp or its derived class. From the preceding discussions, you can easily conclude that when you execute an MFC application, a user-interface thread is started.

Worker Threads

Another type of thread that you can create in an application is the worker thread. Worker threads do not handle user input, but perform background processing for an application. For example, when you create a spreadsheet application, in addition to the user-interface thread, you need to create worker threads to handle certain activities, such as recalculations, drawing graphs, and printing tasks, as background processes. Worker threads do not have message handlers and, therefore, cannot handle any event or window message. An application can have multiple worker threads to handle background processing; however, an application typically has only one user-interface thread.

You are now familiar with the basic concepts of threads, including the need for threads, the types of threaded applications that can be created, and the types of threads. With the basics in place, it’s time for you to learn about how threads are implemented.

More About Threads

Depending on the requirements, you can design either a single-threaded or multithreaded application. Further, in a multithreaded application, you can opt to include multiple user-interface or worker threads. One of the prerequisites for creating a thread in an application is to derive the application class from the CWinThread class so that your application will be capable of handling threads.

To create a thread, you use the AfxBeginThread function of the CWinThread class. The AfxBeginThread function has two overloaded versions: one for worker threads and another for user-interface threads. The next section discusses in detail these overloaded functions.

138

Part I

INTRODUCING VC++.NET

 

 

 

The AfxBeginThread Function for Worker Threads

The syntax for the AfxBeginThread function that you need to use to create a worker thread is as follows:

CWinThread* AfxBeginThread(AFX_THREADPROC ThreadFunction, LPVOID Parameter, int ThreadPriority

=THREAD_PRIORITY_NORMAL, UINT

StackSize = 0, DWORD

ControlFlags = 0,

LPSECURITY_ATTRIBUTES Security = NULL);

Following is a description of the parameters of the AfxBeginThread function:

ThreadFunction. Is substituted by the name of the function that you need to execute with the thread. When you run the thread, it provides the address of this function to the processor. This parameter cannot be NULL because a thread needs at least one function to execute. ThreadFunction must be a global function.

Parameter. Is substituted by any parameters that you need to provide to

the function that you execute with the thread.

ThreadPriority. Specifies the priority that you want to set for the thread. The predefined integer values that you can provide to set the thread priority are displayed in Table 6-1. The threads with the highest priority are executed first.

Table 6-1 Thread Priority Values1

Value

Description

THREAD_PRIORITY_HIGHEST

Specifies the highest priority value for a

 

thread

THREAD_PRIORITY_NORMAL

Specifies the normal priority value for a

 

thread

THREAD_PRIORITY_ABOVE_NORMAL

Specifies one point above the normal

 

priority value

THREAD_PRIORITY_BELOW_NORMAL

Specifies one point below the normal

 

priority value

THREAD_PRIORITY_LOWEST

Specifies the least priority value for a

 

thread

1All the values for the thread priority are predefined integer values.

THREADS

Chapter 6

 

139

 

 

 

 

 

StackSize. Specifies the amount of stack memory (in bytes) that you want to allocate to the thread. When you specify 0 for the StackSize, the default stack size is set equal to the stack size of the thread that creates the current thread.

ControlFlags. Specifies the additional flags that you can specify for the

thread creation. For ControlFlags, you can either specify 0 or CREATE_SUSPENDED values. When you specify 0, the thread starts immediately after it is created, whereas when you specify CREATE_SUSPENDED, the thread is created in a suspended mode. To execute the thread, you need to call the CWinThread::ResumeThread function. You create a suspended thread if you want to initialize any of the member data of the

CWinThread class, such as m_bAutoDelete.

NOTE

m_bAutoDelete is the public data member of the CWinThread class and is of BOOL type. The TRUE value for this data member specifies that the thread is deleted automatically when the thread function terminates.

Security. Specifies the security attributes for a thread and points to the SECURITY_ATTRIBUTES structure. This structure contains the security descriptor for an object. If you specify NULL for the Security parameter, the security attributes of the thread that is creating the current thread are set as the default security attributes.

The AfxBeginThread function returns a pointer of CWinThread type that can be used to control the thread. For example, the pointer enables you to execute the

SuspendThread and ResumeThread functions of the CWinThread class to suspend

and resume the thread, respectively, while your application is running. The pointer also enables you to check the status of the thread.

NOTE

All the macros and constants required by the processes and threads are defined in the winbase.h header file. Therefore, you need to include this header file for the application using threads.