cb199911db_f.asp.htm
来自「C++builder学习资料C++builder」· HTM 代码 · 共 701 行 · 第 1/3 页
HTM
701 行
<HTML>
<HEAD>
<TITLE>Multithreading</TITLE>
</HEAD>
<BODY>
<TABLE border=0 width="100%" cellpadding=0 cellspacing=0>
<TR valign=top>
<TD width="100%">
<p class=ColumnTitle><font size="2">CBuilder
Tech</font></p>
<p class=ColumnSubtitle><font size="2">Multithreading
/ Database Issues</font></p>
<p class=BodyText> </p>
<p class=Byline><font size="2">By Dennis P.
Butler</font></p>
<p class=BodyText> </p>
<p class=StoryTitle><font size="2"><b>Multithreading</b></font></p>
<p class=StorySubtitle><font size="2"><b>Part
II: Multithreaded Queries</b></font></p>
<p class=BodyText> </p>
<p class=BodyText> We've
seen how threads work in general in C++Builder (in Part I of this two-part
article series). In this article's sample program, we'll be running queries in
our threads. The program demonstrates how multithreaded queries work by letting
the user input a query, and launch it as a thread. The results are shown in a
separate window so the user can launch several queries and see how long it takes
each to finish. Users can set the priority of each new query when it's created.
The main screen keeps a running total of all queries that have completed. The
query that's typed into the main screen will execute when the Execute Query button is clicked. </p>
<p class=BodyText> </p>
<p class=BodyText> To
create our new sample program, we must first create a main form. We'll put a <i
style='mso-bidi-font-style:normal'>TComboBox</i> on our form, which we'll fill
with all of our BDE aliases. By doing this, we're allowing users to select the
database alias they wish to query. A <i>TMemo</i>
component is used for users to enter the SQL SELECT statement to be executed.
We're using a <i>TTrackBar</i> component,
just as we used in the previous sample program to control the priority of the
query thread we're creating. A <i>TBitBtn</i>
component is used to create our new custom thread and execute it. We're also
using several <i>TLabel</i> components to
display the results of the query threads we've created. The form we've created
is shown in Figure 1. </p>
<p class=BodyText> </p>
<p class=Captions><img width=333 height=361
src="images/cb199911db_f_image002.jpg" tppabs="http://www.cbuilderzine.com/features/1999/11/cb199911db_f/cb199911db_f_image002.jpg" align=left> <br clear=all>
<b>Figure 1:</b> The threaded query main form. </p>
<p class=BodyText> </p>
<p class=BodyText> The Execute Query button creates a new child form that runs the query and displays
the results. There's also a spin edit control to launch batches of the same
query simultaneously. The database and SQL statement to be executed are passed
as arguments to this child form's <i>Create</i>
statement. </p>
<p class=BodyText> </p>
<p class=BodyText> Because
we're using the <i>TQuery</i> component, we
must meet some new requirements that weren't necessary in the first example -
requirements that apply to any <i>TDataSet</i> component, such as the <i
style='mso-bidi-font-style:normal'>TTable</i>.</p>
<p class=BodyText> </p>
<p class=BodyText> The
first requirement of a multithreaded query is that the query must be contained
within its own BDE session. This is done by using a separate <i
style='mso-bidi-font-style:normal'>TSession</i> component, the component that
controls the interaction with any database. Because a default <i
style='mso-bidi-font-style:normal'>TSession</i> component is automatically
created in all C++Builder projects, single-threaded applications don't require
additional database sessions. In this example, however, we're going to perform
several independent database tasks simultaneously, so we need to create a
separate database session for each. </p>
<p class=BodyText> </p>
<p class=BodyText> To
connect our multithreaded queries with their appropriate <i>TSession</i> components, we'll first create a new <i>TSession</i> component for our multithreaded query, then assign the <i
style='mso-bidi-font-style:normal'>SessionName</i> property of the query to the
name of our newly created <i>TSession</i>
component. In the following example, we explicitly create a <i
style='mso-bidi-font-style:normal'>TSession</i> object to demonstrate what
needs to be set up for the component. It would also have been possible to drop
this component on the form at design time and set up some of the properties
then. In addition to using a separate <i>TSession</i>
component for each <i>TQuery</i> component
to be used in a thread, you must also use a separate <i>TDatabase</i> component and attach it to the new <i>TSession</i> via the <i>SessionName</i>
property of the <i>TDatabase</i>.</p>
<p class=BodyText> </p>
<p class=BodyText> The
second requirement for a multithreaded query is that the threaded <i
style='mso-bidi-font-style:normal'>TQuery</i> component must not be connected
to a <i>TDataSource</i> in the context of
the thread in which it will be executed. This must be done in the context of
the primary thread. </p>
<p class=BodyText> </p>
<p class=BodyText> Now that
we have explained the additional requirements of multithreaded database
applications, we can get back to our sample application. The multithreading
action of this sample application takes place in the <i>frmResults</i> form. This form consists of a <i>TDBGrid</i> to display the query answer set, a <i>TLabel</i> to show messages to the user, and a button to close the
query (see Figure 2). </p>
<p class=BodyText> </p>
<p class=Captions><img width=332 height=233
src="images/cb199911db_f_image003.gif" align=left> <br clear=all>
<b>Figure 2:</b> The result form for the query. </p>
<p class=BodyText> </p>
<p class=BodyText> The
execution of the SQL query that was passed to this form is done by creating a
new thread on the <i>Create</i> method of
the form itself. This makes it easy to launch many different queries. By
passing the SQL statements and database to a new instance of a <i
style='mso-bidi-font-style:normal'>TfrmResults</i> form, a new thread will be
created and executed. </p>
<p class=BodyText> </p>
<p class=BodyText> To
terminate the thread, we'll attach code to the <i>FormClose</i> event of the form. We do this so the thread will be
terminated whether or not it has finished executing. To terminate the thread,
we call its <i>Terminate</i> method. Note
that the only purpose of calling <i>Terminate</i>
is to set the <i>Terminated</i> property of
the thread to <b>true</b>. This by itself doesn't affect the thread. The <i
style='mso-bidi-font-style:normal'>Execute</i> method of the thread must have
logic that checks to see if the thread is terminated, and exit the execution of
the thread if it is, in fact, terminated. </p>
<p class=BodyText> </p>
<p class=BodyText> First we
create a new class, <i>TQueryThread</i>,
which is derived from the <i>TThread</i>
class. Each thread will have several private fields. The thread will need a <i
style='mso-bidi-font-style:normal'>TSession</i> so it has its own handle to the
database, a <i>TQuery</i> that will do most
of the work, a <i>TDataSource</i> to hook
the <i>TQuery</i> to a <i>TDBGrid</i>, and a private reference to the form that created the
thread so it can connect the form's <i>TDBGrid</i>
to the thread's <i>TDataSource</i>. We also
need to override the <i>Execute</i>, <i>Constructor</i>,
and <i>Destructor</i> methods so we can add our own code. The class declaration
for <i>TQueryThread</i> is shown in Figure
3. </p>
<p class=BodyText> </p>
<p class=Code><span class=Code><b>class</b>
TQueryThread: <b>public</b> TThread</span></p>
<p class=Code><span class=Code>{</span></p>
<p class=Code><span class=Code> <b> private</b>:</span></p>
<p class=Code><span class=Code> TSession *FSession; <i><span Class=CodeBlue>// Our Unique Database Session. </span></i></span></p>
<p class=Code><span class=Code> TQuery *FQuery; <i><span Class=CodeBlue>// The Results Query. </span></i></span></p>
<p class=Code><span class=Code> TDatabase *FDatabase <i> <span Class=CodeBlue>// The Database Component. </span></i></span></p>
<p class=Code><span class=Code> TDataSource *FDataSource; <i
style='mso-bidi-font-style:normal'><span Class=CodeBlue>// Our Query
Datasource. </span></i></span></p>
<p class=Code><span class=Code> TForm *FOwnerForm; <i><span Class=CodeBlue>// The Query Results form itself. </span></i></span></p>
<p class=Code><span class=Code> AnsiString FErrorMsg; <i><span Class=CodeBlue>// Error message variable. </span></i></span></p>
<p class=Code><span class=Code> <b> protected</b>
: </span></p>
<p class=Code><span class=Code> <b> void</b>
<b>__fastcall</b> Execute(); <i
style='mso-bidi-font-style:normal'><span Class=CodeBlue>// Override default
Execute Method. </span></i></span></p>
<p class=Code><span class=Code> <b> public</b>
: </span></p>
<p class=Code><span class=Code> <b> virtual</b>
<b>__fastcall</b> TQueryThread(TForm
*AOwner, </span></p>
<p class=Code><span class=Code> TStrings *SQLStrings, AnsiString
DatabaseName, </span></p>
<p class=Code><span class=Code> <b> int</b>
intPriority); <i
style='mso-bidi-font-style:normal'><span Class=CodeBlue>// Custom Create
method. </span></i></span></p>
<p class=Code><span class=Code> <b> __fastcall</b>
~TQueryThread();</span></p>
<p class=Code><span class=Code> <b> void</b>
<b>__fastcall</b> DisconDataSource(); <i> <span Class=CodeBlue>// Disconnect datasource. </span></i></span></p>
<p class=Code><span class=Code> <b> void</b>
<b>__fastcall</b> ConnectDataSource(); <i
style='mso-bidi-font-style:normal'><span Class=CodeBlue>// Connect the
datasource. </span></i></span></p>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?