📄 cb199910db_f.asp.htm
字号:
<HTML><HEAD><TITLE>Multithreading</TITLE>
<BODY bgColor=white leftMargin=0 topMargin=0 MARGINWIDTH="0" MARGINHEIGHT="0">
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR vAlign=top>
<TD width="100%">
<P class=ColumnSubtitle><b>Multithreading / Database Issues</b></P>
<P class=Byline>By Dennis P. Butler</P>
<P class=StoryTitle>Multithreading</P>
<P class=StorySubtitle>Part I: Introducing C++Builder Multithreading </P>
<P class=BodyText> </P>
<P class=BodyText>One of the most important features of Microsoft's 32-bit
operating systems is a mechanism known as <I>multithreading</I>. With
Windows 95/98/NT, Microsoft has given developers the ability to create
programs capable of doing more than one process at a time. In the 16-bit
architecture of Windows 3.x, separate applications run at the same time in
a cooperative multitasking environment. This means that a single
application can use all of the CPU time, occasionally checking the Windows
queue to see if it should give up control of the CPU to another
application. </P>
<P class=BodyText> </P>
<P class=BodyText>This differs from the preemptive multitasking
architecture of Windows 95/98/NT. In these 32-bit environments, each
running application is referred to as a <I>process</I>. Each process can
consist of one or more threads that are portions of executable code from
the application. It's called preemptive multitasking because control of
the CPU is determined by the needs of the system and the threads running
on it. Each of the threads gets a certain portion of processing time from
the CPU, which allows it to be run with other threads. By doing this, the
processor can handle multiple threads at once, processing them according
to the amount of CPU time they've been allocated. Using multithreading
programming techniques, processes can run more efficiently and
consistently for the users of an application. </P>
<P class=BodyText> </P>
<P class=BodyText>C++Builder gives application developers the ability to
easily take advantage of this new technology through the framework of the
<I>TThread</I> class. Programmers can now maximize application efficiency
by taking advantage of multiple threads in their applications rather than
having to run one process at a time. A host of possibilities is now
available, from background processing of data, to prioritizing certain
tasks over others. Now developers can rapidly create and deploy
multithreading applications using C++, as opposed to the more complicated
methods that have been required in the past. Because the programmer is
given access to the low-level functionality of the operating system
architecture through using threads, it's important to fully understand the
mechanisms behind threads and when they should be used. </P>
<P class=BodyText> </P>
<P class=BodyText>This two-part article series will describe and
demonstrate how and when to correctly use multithreaded database
applications in C++Builder. Part I introduces the basics, and creates a
sample multithreaded application. Part II goes on to use the techniques in
a more complex, and "real world" fashion, i.e. to perform multithreaded
database queries. </P>
<P class=BodyText> </P>
<P class=Subheads>Thread Basics 101</P>
<P class=BodyText>To start with, it's important to understand thread
concepts and terminology. As mentioned previously, an application is
referred to as a process. Individual paths of execution within that
process are referred to as threads. An example of how multithreading works
in the 32-bit architectures of Windows 95/98/NT is demonstrated by the
ability to perform tasks in the foreground of Windows while you're copying
files in the background. 16-bit Windows doesn't allow this to occur, but
rather gives total control to either the foreground process, or the
background copy process. </P>
<P class=BodyText> </P>
<P class=BodyText>The overall purpose of multithreading is to allow an
application to continue to operate while other tasks are taking place.
This is an important feature, especially when a particular thread can take
a long time to execute, and may be of a generally low priority. By running
multiple threads, users of an application have access to the most
important parts of the program while it's running something else
concurrently. </P>
<P class=BodyText> </P>
<P class=BodyText>Win32 environments use preemptive multitasking to
determine that threads are going to have CPU processing time. The
determination of the thread to execute is controlled by the Windows
scheduler. Preemptive multitasking gives a small time slice of CPU time to
each thread based on its priority. The thread queue is built based on the
individual threads within it. For example, take an environment where two
threads have the highest level of thread priority, and two other threads
have the next lower thread priority. If a new thread with the highest
thread priority is inserted into the queue, the scheduler will put the new
thread in front of the two other threads with the next lower priority.
It's by using this weighted queue method that the Windows scheduler
determines which threads are going to be processed next. </P>
<P class=BodyText> </P>
<P class=BodyText>The very nature of threads lends itself to problems when
used incorrectly in applications. Thread starvation and thread deadlock
are two of the more common problems. It's important to keep these
potential problems in mind when designing a multithreaded application.
These problems - and how to solve them - will be described later in the
article. </P>
<P class=BodyText> </P>
<P class=BodyText>Although multithreading is a low-level programming
technique, C++Builder has encapsulated the functionality of threads into
the <I>TThread</I> object. By doing this, programmers can safely implement
threads in their applications and take full advantage of their performance
benefits without worrying about low-level concerns, such as cache
coherency and memory locking. Because this article is intended as an
introduction to threading techniques, we won't cover threading outside of
the <I style="mso-bidi-font-style: normal">TThread</I> class due to the
complexity of the topic. </P>
<P class=BodyText> </P>
<P class=BodyText>To demonstrate an example of where a multithreaded
database application would be beneficial, let's look at a situation where
we have an application with several databases. Consider a company that
sells software to businesses through phone orders. It has an application
that can handle the data input of the orders, and generate invoices for
those orders for any specified period of time. Each week, invoices have to
be generated for the software that was sold. If the computer is
calculating all the invoices, and a new customer calls and wants to place
an order, the user doesn't want to halt the invoice process just so new
information can be entered. </P>
<P class=BodyText> </P>
<P class=BodyText>This is a common business problem that can be solved by
using multiple threads. One thread will be created for the application.
Then, instead of using this same thread for the invoices, a new thread
will be generated with a lower priority than the application thread. The
invoices will continue to be calculated in the background, but the user of
the system will now have access to the rest of the application and can
take the phone order that came in. </P>
<P class=BodyText> </P>
<P class=BodyText>Part of the beauty of threads is that different levels
of priority can be set to each thread. For example, if the program must be
very quick when taking information (from a phone order in this case), the
main thread that handles this will be given a high priority compared to
the other threads in the application. The invoice calculation will process
at normal speeds while nothing else is being done in the application. When
something else is happening, however, it gets the lowest amount of CPU
access. </P>
<P class=BodyText> </P>
<P class=Subheads>C++Builder Database Objects</P>
<P class=BodyText>Before we can demonstrate how to create multithreaded
database applications, we must review the database objects themselves. The
C++Builder components, <I style="mso-bidi-font-style: normal">TTable</I>
and <I>TQuery</I>, will be used in this article. The <I>TTable</I>
component is a pointer to a data structure, whether it's a client/server
or local table. In the sample applications we'll review, the tables used
are local Paradox tables installed as examples by C++Builder. (Local
tables were chosen instead of client/server ones in the interest of
keeping the data structures simple. The <I>TThread</I> object will work in
the same manner for local and client/server tables.) </P>
<P class=BodyText> </P>
<P class=BodyText>The <I style="mso-bidi-font-style: normal">TTable</I>
components we're using in our threads are created at run time, and set up
with their appropriate aliases and table names. Our sample applications
also use the <I>TQuery</I> component. <I>TQuery</I> allows users to query
or modify a data structure based on particular criteria by using SQL code.
In the case of both the <I>TQuery</I> and <I>TTable</I> components, there
is a property named <I>SessionName</I> that must be set to the session of
the database thread that is created. Using <I
style="mso-bidi-font-style: normal">SessionName</I> will be described in
more detail later. These two components are the basis for creating
database applications using C++Builder. </P>
<P class=BodyText> </P>
<P class=Subheads>The <I>TThread</I> Class</P>
<P class=BodyText>Now that we've reviewed the background information
necessary to understand multithreading, lets look at the C++Builder
interface to create multiple threads. The object that creates and
manipulates threads is the <I
style="mso-bidi-font-style: normal">TThread</I> object. The <I>TThread</I>
object has many properties and methods to handle threads. Let's review the
ones that are applicable. </P>
<P class=BodyText> </P>
<P class=Subheads>Properties</P>
<P class=BodyText>A <I style="mso-bidi-font-style: normal">TThread</I>
class is just like any C++Builder class, and has a <I>Constructor</I> and
<I>Destructor</I> method for creating and freeing the particular instance
of the thread. Because each thread a user will create is a new task being
accomplished, we'll usually overwrite portions of the thread object each
time we want to create a new thread. This is because we'll usually want to
pass information or objects to the thread to be processed. To do this we
must customize the structure of the object to handle this information. The
standard procedure and properties of the thread object we create will
still be available for use. Let's review the properties of our standard
<I>TThread</I> object. </P>
<P class=BodyText> </P>
<P class=BodyText>Because the Win32 API has many functions that can be
used in manipulating a thread, the <I>TThread</I> object has a read-only
property named <I>Handle</I>. This property can be used in any API call
that requires the thread handle as a parameter. By having this available,
a programmer can take advantage of any additional thread functionality he
or she may wish to include in an application. The value for this property
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -