看本文時,可以同時參考:Delphi中線程類 TThread實現多線程編程(事件、臨界區、Synchronize、WaitFor……)
先說一下RTL和VCL
RTL(Run-Time library),運行時庫,包括System、SysUtils、Math三個單元,提供的函數與語言、編譯器、操作系統及進程有關
RTL提供類之間繼承於 TObject 和 RTL內部的類
VCL(Visual Component Library),可視化組件庫,包括Graphics、classes、Controls等與類和組件相關的單元
VCL不是線程安全的
因為VCL不是線程安全的,所以對VCL的訪問只能在主線程中。這將意味着:所有需要與用戶打交道的代碼都只能在主線程的環境中執行。這是其結構上明顯的不足,並且這種需求看起來只局限在表面上,但它實際上有一些優點
開發多線程項目的主要需要考慮的一點就是同步多線程使用資源,不要產生沖突,其實想Delphi的VCL組件也是一種資源,但是VCL不是線程安全的,不能讓其他的線程使用,只能通過主線程來使用它
1.可能的一個應用場景
比如在開發圖形化界面的項目中,需要連接數據庫,可以采用這樣的策略:用主線程來繪制組件到圖形化界面,而連接數據庫的過程在子線程中實現。
這時候能夠保證就算在連接數據庫的時候出現問題,子線程可能會去嘗試一直連接,但是因為各個線程之間互不相干,各自執行各自的邏輯代碼,所以不影響主線程繪制組件,所以窗體並不會卡住
但是可能要在子線程中讀取數據庫中的數據來展示數據,這個時候,因為VCL 不是線程安全的,所以不能允許主線程(繪制組件)和子線程(想要去將從數據庫中的數據“寫”到界面上)同時去操作組件
所以可能的解決方法(見 3.Synchronize() 方法)就是 使用Synchronize() 方法來調用子線程想要將數據“寫到”界面的方法,這樣就能保證這個方法實際上是在主線程中執行的(雖然它是子線程的方法,但是通過Synchronize() 方法可以實現將子線程的方法放到主線程中執行),這樣就能保證不會出現多個線程使用VCL 組件
2.單線程用戶界面的好處
首先,只有一個線程能夠訪問用戶界面,這減少了編程的復雜性。Win32 要求每個創建窗口的線程都要使用 GetMessage() 建立自己的消息循環。正如你所想的,這樣的程序將會非常難於調試,因為消息的來源實在太多了
其次,由於 VCL只用一個線程來訪問它,那些用於把線程同步的代碼就可以省略了,從而改善了應用程序的性能
3.Synchronize() 方法
在 TThread中有一個方法叫Synchronize(),通過它可以讓子線程的一些方法在主線程中執行。Synchronize() 的聲明如下
1
|
procedure
Synchronize(Method: TThreadMethod);
|
參數Method 的類型是 TThreadMethod(這是一個無參數的過程),類型的聲明如下
1
2
|
type
TThreadMethod =
procedure
of
object
;
|
Method參數用來傳遞在主線程中執行的方法。以 TTestThread對象為例,如果要在一個編輯框中顯示計算的結果。首先要在TTestThread中增加能對編輯控件的Text 屬性進行修改的方法,然后,用Synchronize() 來調用此方法
給這個方法取名 GiveAnswer(),下面列出例子的代碼,其中包含了更新主窗體的編輯控件的代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
unit
ThrdU;
interface
uses
Classes;
type
TTestThread =
class
(TThread)
private
Answer:
Integer
;
protected
procedure
GiveAnswer;
procedure
Execute; override;
end
;
implementation
uses
SysUtils, Main;
{TTestThread}
procedure
TTestThread
.
GiveAnswer;
begin
MainForm
.
Edit1
.
Text := IntToStr(Answer);
end
;
procedure
TTestThread
.
Execute;
var
I:
Integer
;
begin
FreeOnTerminate:=
True
;
for
I:=
1
to
2000000
do
begin
if
Terminated
then
Breadk;
Inc(Answer, Round(
Abs
(Sin(Sqrt(I))));
Synchronize(GiveAnswer);
end
;
end
;
|
Synchronize() 的作用是在主線程中執行一個方法。
當你在程序中第一次創建一個附屬線程時,VCL 將會從主線程環境中創建和維護一個隱含的線程窗口。此窗口唯一的目的是把通過Synchronize() 調用的方法排隊
Synchronize() 把由Method 參數傳遞過來的方法保存在 TThread的 FMethod字段中,然后,給線程窗口發送一個CM_EXECPROC消息,並且把消息的lParam 參數設為self(這里是值線程對象)。當線程窗口的窗口過程收到這個消息后,它就調用 FMethod字段所指定的方法。由於線程窗口是在主線程內創建的,線程窗口的窗口過程也將被主線程執行。因此,FMethod字段所指定的方法就在主線程內執行
下圖形象地說明了 Synchronize() 的內部機制和原理
、
4.用消息來同步
可以利用在線程之間使用消息同步以替代 TThread.Synchronize() 方法。可以使用API 函數SendMessage() 或 PostMessage() 來發送消息。例如下面一段用來在一個線程中設置另一個線程中的編輯框文本的代碼
1
2
3
4
5
6
|
var
S:
String
;
begin
S:=
'hello from threadland'
;
SendMessage(SomeEdit
.
Handle, WM_SETTEXT,
0
,
Integer
(
PChar
(S)));
end
;
|
http://www.cnblogs.com/xumenger/p/4505104.html