In the beginning, it should have been a simple article, but I still advocate doing it first and understanding it in trying.
First try this:
ProcedureTform1.button1click (Sender: tobject );
VaR
I: integer;
Begin
ForI: =0 To 500000 Do
Begin
Canvas. textout (10,10, Inttostr (I ));
End;
End;
AboveProgramAt runtime, our form is basically "dead". You can try dragging the form while you are running...
Delphi provides us with a simple solution (application. processmessages) to solve this problem:
ProcedureTform1.button1click (Sender: tobject );
VaR
I: integer;
Begin
ForI: =0 To 500000 Do
Begin
Canvas. textout (10,10, Inttostr (I ));
Application. processmessages;
End;
End;
This application. processmessages is generally used in a time-consuming cycle. It checks and processes other messages in the message queue first.
But this is not a multi-thread. For example, if you drag a form during running, the loop will be paused...
Before using multithreading, let's simply modify the program:
Function Myfun: integer;
VaR
I: integer;
Begin
For I: = 0 To 500000 Do
Begin
Form1.canvas. lock;
Form1.canvas. textout ( 10 , 10 , Inttostr (I ));
Form1.canvas. Unlock;
End ;
Result: = 0 ;
End ;
Procedure Tform1.button1click (Sender: tobject );
Begin
Myfun;
End ;
Program changes:
1. First, this is not multi-threaded, and it will make the form fake "dead" for a while;
2. RunCodeIt is written in a function, but this function does not belong to the tform1 method. Therefore, the canvas must be named (form1 );
3. Since it is a function (whether necessary or not), there should be a return value;
4. 500001 locks and unlocks are used.
Canvas. Lock is like saying: canvas (drawing surface) is busy, and others want to use canvas;
Canvas. Unlock: unlocked!
It is a good habit to use lock and unlock in the canvas. It doesn't matter if you don't use multiple threads, but it's not certain which program will be extended to multiple threads. We are now learning multithreading, of course we should use it.
There are two methods to use multithreading in Delphi: calling the API and using the tthread class; using the API code is simpler.
Function Myfun (P: pointer): integer; Stdcall ;
VaR
I: integer;
Begin
For I: = 0 To 500000 Do
Begin
Form1.canvas. lock;
Form1.canvas. textout ( 10 , 10 , Inttostr (I ));
Form1.canvas. Unlock;
End ;
Result: = 0 ;
End ;
Procedure Tform1.button1click (Sender: tobject );
VaR
ID: thandle;
Begin
Createthread ( Nil , 0 , @ Myfun, Nil , 0 , ID );
End ;
Code Analysis:
After createthread a thread, calculate the original main thread, so that the program has two threads and is a standard multi-thread;
The third parameter of createthread is the function pointer. After a new thread is created, the function will be executed immediately. After the function is executed, the system will destroy the thread and end the multi-thread process.
Createthread uses a system-level function. It cannot be a class (such as tform1) method, and has strict format (parameters and return values) requirements, whether you need it or not, it must be in the format;
Because it is a system-level call, stdcall must be appended. stdcall coordinates the order of parameters. Although there is only one parameter, there is no order, but this is the practice of using system functions.
Createthread also requires a VaR parameter to accept the ID of the new thread. Although it is useless for the time being, it is also in the format. Let's talk about other parameters later.
This is the simplest multi-threaded program. We can use the tthread class to implement it once.
Type
Tmythread = Class (Tthread)
Protected
Procedure Execute; Override ;
End ;
Procedure Tmythread. Execute;
VaR
I: integer;
Begin
Freeonterminate: = true; {This allows the thread to be released immediately after execution}
For I: = 0 To 500000 Do
Begin
Form1.canvas. lock;
Form1.canvas. textout ( 10 , 10 , Inttostr (I ));
Form1.canvas. Unlock;
End ;
End ;
Procedure Tform1.button1click (Sender: tobject );
Begin
Tmythread. Create (false );
End ;
The tthread class has an abstract method (execute), so it is an abstract class. The abstract class can only be inherited and used. The above class is inherited as tmythread.
Inheritance of tthread is mainly to implement the abstract method execute (write our code in it). After our tmythread is instantiated, the code in the execute method will be executed first.
In general, we will instantiate it like this:
ProcedureTform1.button1click (Sender: tobject );
VaR
Mythread: tmythread;
Begin
Mythread: = tmythread. Create (false );
End;
Because the mythread variable is useless here (and the compiler still prompts), it is better to directly write tmythread. Create (false );
We can also easily solve a problem if: tmythread. Create (true )?
In this way, execute will not be called immediately after the thread is created. You can use the resume method to execute the thread as needed, for example:
ProcedureTform1.button1click (Sender: tobject );
VaR
Mythread: tmythread;
Begin
Mythread: = tmythread. Create (true );
Mythread. Resume;
End;
// Simplified:
ProcedureTform1.button1click (Sender: tobject );
Begin
WithTmythread. Create (true)DoResume;
End;
When using the tthread class, Delphi provides a template, but it is very convenient to write code with ide. I will rewrite it and record it for you:
The shortcut keys include Ctrl + J, Shift + Ctrl + C, and CTRL + ALT + P.
Important amendments and supplements:
In the example of the tthread class, we should have the following sentence: freeonterminate: = true; (it was omitted in the code, but the animation cannot be added ).
What does it mean first:
Class create requires free;
However, tthread (subclass) has special characteristics. In many cases, we cannot determine when the newly created thread will be executed (that is, when to release it );
If the thread execution is complete, it knows to release it. Therefore, tthread gives freeonterminate a Boolean attribute. If it is true, it will be released after the thread execution is complete.
How can I ignore such an important issue? There are two reasons:
1. I have been pursuing the most refined code;
2. I have explained in more than one book that the default value of freeonterminate is true (Error!), The implementation should be false, at least in Delphi 2007 and 2009; maybe a previous version is different from the current version.