[Details] multi-thread processing in Delphi
Http://hi.baidu.com/boxroom/blog/item/97a82a3fea4606e554e7239f.html
When there are too many threads, there are too many threads, too many threads.
1-1 Basic concepts of Multithreading
Multithreading brings the following benefits: (read by yourself)
1) avoid bottlenecks;
2) parallel operations;
3) improve efficiency;
In multithreading, priority management can give priority to important programs and improve the flexibility of task management.
On the other hand, in a multi-CPU system, different threads can be executed in different CPUs to truly process multiple tasks at the same time (Win 98 is just a simulation, win/NT/2000 is the real multi-CPU operation at the same time ).
Two concepts of multithreading:
1) process: it is also called a task. A program loads memory and allocates resources, which is called a "process ".
Note: The process itself does not have to be executed. A process consists of the following parts:
A> a private address space, which is a set of virtual memory address spaces that can be used by processes;
B> code and data sources of the program;
C> system resources, such as operating system synchronization objects;
D> contains at least one thread (main thread );
2) thread: it is the execution unit of the program (the thread itself does not include the program code, but the process that actually owns the Code). Each process includes at least one thread, called the main thread, if a process has multiple threads, the resources of the same process can be shared and executed concurrently.
A thread is an execution unit of a process and the basic entity for the CPU time allocated by the operating system. A thread consists of the following two parts:
A> data structure;
B> CPU registers and stacks;
A thread in a process can run independently or control the running of another thread.
Note:
Multithreading cannot be abused. The book mentions several shortcomings of multithreading (self-reading ).
1-2 Tthread object
Although Windows provides a lot of multi-threaded API functions, the direct use of API functions is extremely inconvenient, and improper use is prone to errors. To solve this problem, Borland first launched a Tthread object to solve the difficulties in multithreading design and simplify the processing of multithreading problems.
It should be noted that the Tthread object does not have an instance. It communicates with the interface, mainly relying on the main form (main VCL thread), which is somewhat different from other objects.
I. Main Methods of Tthread objects
Constructor thread:
Constructor Create (createsuincluded: boolean)
Where: createsuincluded = true is constructed but does not wake up
When the value is set to false, the system wakes up.
You can also use the following method
Inheried Create (createsuincluded: boolean)
Suspended thread: suspend
(Increase the number of threads suspended by one)
Wake-up thread:
Resume
(Note: This attribute reduces the number of threads suspended by one. When the number of threads is 0, it is awakened. That is to say, the number of thread hangs and the number of wake-up requests. When the thread is suspended, the address pointer of the thread remains unchanged. Therefore, the thread will be awakened after being suspended and will start running from the suspended place)
Destructor (clears the memory occupied by the thread ):
Destroy
Terminate the thread (which will be discussed later ):
Terminate
Ii. Simple Example of thread application:
The following example shows the application of the above method. We know that loop is one of the most dedicated running modes. Now we want to create two thread objects to achieve Parallel Running of the loop. The specific method is as follows:
File --- New --- Thread Object
This automatically creates a thread unit in the main Form (write the thread name in the dialog box). The default name is unit2. The second thread unit unit3.
Note that Unit2 and Unit3 have a given process:
Procedure Object. Execute;
Begin
End;
The program is automatically executed after the thread is awakened. You can also call other custom processes and functions. The end of this process means the end of the thread program.
To construct a thread, define a construction process in the interface Type area:
Type
Object = class (TThread) // automatically provided, you can also directly change
Private
Protected
Procedure Execute; override;
Public
Constructor create; // self-written
In the implementation area, write:
Constructor Object. create;
Begin
Inherited create (true );
End
The Object is the name of the thread Object. Therefore, we hope to call this constructor in the main Form.
The Create () parameter uses True to indicate that the constructed thread is suspended.
Note: In the same thread object, if two constructor operations are performed, two independent threads are generated. Not only are the running tasks independent, but the local variables of the thread are also independent. However, to simplify the problem, two independent thread objects are created, and the number of loops is different. During parallel operations, it is easy to determine that two different programs are running.
Assume that the names of the two thread objects are:
Mymath1
Mymath2
In Unit1, the following statement should be made:
Implementation
{$ R *. DFM}
Uses unit2, unit3;
Var thread1: mymath1;
Thread2: mymath2;
In this way, the corresponding thread method can be called through these two thread variables in the main thread.
The method for constructing a thread in the main thread area is as follows:
Thread1: = mymath1.create;
Thread2: = mymath2.create;
Pending:
Thread1.suspend;
Thread2.suspend;
Wake up:
Thread1.resume;
Thread2.resume;
Analysis structure:
Thread1.destroy;
Thread2.destroy;
It should be noted that because the thread unit needs to call the Edit Control (object) of Form, two methods can be used:
1) define a TEdit object in the thread unit, for example
Edit4: Tedit;
Direct reference during Execute
However, in Unit1, you must assign a value in the FormCreate process:
Procedure TForm1.FormCreate (Sender: TObject );
Begin
Thread1.edit4: = edit1;
End;
In this way, associate edit4 In the first thread with edit1 in the Form.
2) Declare the call to Unti1 In the second thread, that is, add
Uses Unit1;
In this way, you can directly call the control of the main Form in this thread unit. For example, you can write in unit3:
Form1.edit2. text: = inttostr (I)
After learning about these basic rules, you can write complicated multi-threaded programs.
Another note is that the thread unit generated by default has only one calling Unit:
Uses Classes;
In this way, many functions and objects are often not used in thread units. Therefore, when necessary, the User-related units should be used. This routine is simple, copying most of the commonly used units is not recommended because it will cause too much garbage in the program.
Iii. Common API functions
When dealing with multithreading, Apis provided by Windows are often used. It should be noted that the internal encapsulation method of the Tthread object mainly calls API functions. However, more comprehensive and safer. Directly Calling API functions may lead to some unexpected errors due to improper use. Therefore, I personally think that as long as the Tthread object method can be used to solve the problem, do not directly call the API function. The API function should only be used when the Tthread object method cannot solve the problem.
For example, when the Tthread object method calls an API function internally, the Recommended default value is generally used, but you can directly use the API function when you need more precise control.
In fact, the Tthread object method has been recognized by most programmers. For example, VB does not have the ability to directly process multiple threads. net declared that it has the ability to easily handle multithreading issues, which is a clear explanation of the problem.
The following describes several API functions. For clarity and convenience, we will focus on the description. You can read the examples and manuals in the book for the correct description of the functions:
Build thread:
CreateThread (parameter 1, -- Security Attribute (generally = Nil, default security attribute)
Parameter 2, -- thread stack size (generally = 0, same length as the main thread, and can be automatically changed as needed)
Parameter 3, -- point to the Function Name Pointer, @ function name. This parameter is very important and cannot be called successfully if it is incorrect.
Parameter 4, -- the parameter that the user needs to pass to the thread. It is a pointer to the structure and Nil is used when no parameter is required.
Parameter 5) -- input some thread-related parameters, for example:
Create_suincluded creates a suspended thread;
0 is activated immediately after creation.
There are clear examples of this function application in the book. You can read it by yourself.
It is generally not recommended to use the CreateTheard function, but it is recommended to use the BeginTheard function defined in the System unit in the RTL library, because in addition to creating a thread and an entry function, several protection measures have been added. For details, refer to the 10th page in the book.
The two API functions corresponding to suspend and resume are:
Function SuspendThread (hThread: Thandle): DWORD;
Function ResumeThread (hThread: Thandle): DWORD;
Among them, Thandle is required to control the thread handle. The function call is successful, the number of hangs is returned, and the call is unsuccessful. 0 xFFFFFFFF is returned.
4. Termination and exit of a thread:
1) automatically Exit:
A thread exits from the Execute () process, which means that the thread is terminated. At this time, the Windows ExitThread () function is called to clear the stack occupied by the thread.
If the FreeOnTerminate attribute of the thread object is set to True, the thread object is automatically deleted and the resources occupied by the thread are released.
This is the easiest way to eliminate thread objects.
2) Controlled Exit:
The Terminate attribute of a thread object can be used to control the exit of a thread by a process or another thread. You only need to call the Terminate method of the thread and set the Terminate attribute of the linear program object to True.
In the thread, you should constantly monitor the value of Terminate. Once it is found to be True, exit. For example, during the Execute () process, you can write as follows:
While not Terminate do
Begin
........
End;
3) exited API functions:
The API function declaration for thread exit is as follows: code
Function TerminateThread (hThread: Thandle; dwExitCode: DWORD );
However, this function will immediately terminate the Code, regardless of whether the program has
Try... finally
Mechanism, which may cause errors.
4) use the thread suspension method (suspend)
Use the suspend method of the suspended thread, followed by a Free thread, you can also release the thread,
For example:
Thread1.suspend; // pending
Thread2.free; // release
There are examples in the book.
5. thread priority:
In the case of multithreading, it is generally necessary to give the thread a proper priority based on the importance of the thread to execute the task. Generally, if the number of threads simultaneously request the CPU time, the thread with a higher priority takes precedence.
In Windows, the priority of a thread is divided into 30 levels, while in Delphi, the priority of a Tthread object is generally divided into seven levels. That is, an enumeration type TTthreadPriority is declared in Tthread:
Type
TTthreadPriority (tpidle, tpLowest, tpLower, tpNormal,
TpHight, tpHighest, tptimecrest)
They correspond to the lowest (valid when the system is idle,-15), low (-2), low (-1), normal (normal 0), high (1 ), relatively high (2), maximum (15 ).
The tpidle and tpTimecrital are somewhat special. For details, please read the relevant content in the book.
To set the priority, you can use the priority attribute of the thread object:
ThreadObject. priority: = Tthreadpriority (level );
Here is an example showing the priority of multithreading:
1-3 use multithreading in the database
1) Use the ADO Mode
Since the ADO Data Source Control of Delphi 6.0 has built-in multithreading capabilities, you do not need to do more work to use multithreading In the ADO mode. Use two ADOTable controls to connect to two databases respectively, and use the DataSource control to contact the data help control, so that the front and back end can handle database problems.
2) use the BDE mode and Tseeion object
If you need to use the BDE mode, you need to consider the Session issue when using the database with multiple threads. In a single thread, a Session is automatically generated when each data source is created. This is a private file about the database information of the data source. But when multithreading is required, it must be managed in a unified manner. Therefore, a Tsession object is provided in BDE, which can manage different Databas data source objects at the same time.
Databas data sources can accept databases from different data platforms.
Database 1 --- databas (2) ---- table (Qurey) (3) --- datasource
|
|
| --------- Tsession (1)
|
|
Database 2 --- databas (2) ---- table (Qurey) (3) --- datasource
Method:
1) Tsession
Attribute: SessionName = Name (from)
Active = true (activated)
2) Database (multiple databases are allowed)
Attribute: SessionName = Tsession name
Dataname = Name (self-initiated, used as the Table identifier)
AliasName = database alias
Connected = True (activated)
3) Table or Qurey
Attribute: SessionName = Tsession name (do not use the default value)
DatabaseName = if the previous name is set, the Database will appear here
.
Tablename = table name
Active = true (activated)
In the future, for example, adding datasoure to the database is the same as other databases. In this way, we can construct two database management systems processed by the front and back ends.
2-4 multi-thread synchronization mechanism
The synchronization mechanism is actually an event-driven mechanism, which means that the thread is in the "Sleep" state at ordinary times unless an event occurs.
For example, when a copy file is copied, the copy thread completes a program block and then wakes up the process thread to fill in a cell.
The necessity of studying the multi-thread synchronization mechanism is that if the same resource is called at the same time during multi-thread synchronization, problems may occur. Generally, reading is not problematic. However, if the data is written (global variables and databases), a conflict or even death occurs.
Lock and competition issues.
1. Use the Synchronize Method
This method is used to access resources managed by the VCL main thread. The application of this method is:
Step 1: Put the code for accessing the main window (or the main window control resource) into a method of the thread;
Step 2: Use the Synchronize method in the Execute method of the thread object.
Instance:
Procedure Theater. Execute;
Begin
Synchronize (update );
End;
Procedure Theater. update;
Begin
.........
End;
Synchronize is used to Synchronize the update of the thread method.
Ii. Use the Look method of VCL class
Among the components provided by Delphi IDE, some objects provide the thread synchronization mechanism, which can be directly used by working threads, such as Tfont, Tpen, TBitmap, and TMetafile, ticon. In addition, a very important control object called TCanvas provides a Lock method for thread synchronization. When a thread uses this control object, it first calls the Lock method of this object, then, the control is operated, and then the Unlock method is called to release control of the control room.
For example:
CanversObject. look;
Try
Drawing
Finally
CanversObject. unlock;
End;
{Use this protection mechanism to ensure that unlock will be executed no matter whether there is any exception or not. Otherwise, a deadlock may occur. When designing multiple threads, pay attention to the deadlock problem}
Iii. Waitfor Method
You can call the Waitfor method when a thread waits for the end of another thread. This method is a waiting thread object. The prototype of the Waitfor method is as follows:
Function Waitfor (Const Astring: string): string;
For example, in the preceding basic thread example, add
Thread1.resume;
Thread1.waitfor;
Thread2.resume;
All threads can only run after thread1 is completed, including the main thread. As expected, since thread1 calls the Edit control of the main form, edie1 is not displayed either.
This tells us that such Code cannot be part of the main thread. If the thread connected to the main form waits for the end of another thread, and the other thread waits for access to the user interface, the program may be deadlocked.
This should be used with caution.
4. Use Windows APIs for synchronization
Windows API functions provide many synchronization technologies. The following is a brief introduction.
1) critical section
A basic problem encountered when using a thread is that multiple threads access the same object, such as accessing the same file, DLL, and communication resources, especially database access, when multiple threads write data to the same database field
Current uncertainty.
The critical section is used to solve this problem. It ensures that when the thread uses sensitive data, it will prevent other threads from accessing the dry name data. Initialization is required before use. It declares a variable of the TRTLCriticalSection type:
Var
CS: TRTLCriticalSection;
Initialization:
InitializeCriticalSection (cs );
Exclusive
EnterCriticalSection (cs );
Exclusive relief
LeaveCriticalSection (CS );
The use of critical zones is a convenient and well-defined thread synchronization mechanism and is widely used.
When there are too many threads, there are too many threads, too many threads.