看本文時,能夠同時參考:Delphi中線程類 TThread實現多線程編程(事件、臨界區、Synchronize、WaitFor……)html
先說一下RTL和VCL數據庫
RTL(Run-Time library),運行時庫,包括System、SysUtils、Math三個單元,提供的函數與語言、編譯器、操做系統及進程有關編程
RTL提供類之間繼承於 TObject 和 RTL內部的類安全
VCL(Visual Component Library),可視化組件庫,包括Graphics、classes、Controls等與類和組件相關的單元多線程
VCL不是線程安全的ide
由於VCL不是線程安全的,因此對VCL的訪問只能在主線程中。這將意味着:全部須要與用戶打交道的代碼都只能在主線程的環境中執行。這是其結構上明顯的不足,而且這種需求看起來只侷限在表面上,但它實際上有一些優勢函數
開發多線程項目的主要須要考慮的一點就是同步多線程使用資源,不要產生衝突,其實想Delphi的VCL組件也是一種資源,可是VCL不是線程安全的,不能讓其餘的線程使用,只能經過主線程來使用它性能
1.可能的一個應用場景spa
好比在開發圖形化界面的項目中,須要鏈接數據庫,能夠採用這樣的策略:用主線程來繪製組件到圖形化界面,而鏈接數據庫的過程在子線程中實現。操作系統
這時候可以保證就算在鏈接數據庫的時候出現問題,子線程可能會去嘗試一直鏈接,可是由於各個線程之間互不相干,各自執行各自的邏輯代碼,因此不影響主線程繪製組件,因此窗體並不會卡住
可是可能要在子線程中讀取數據庫中的數據來展現數據,這個時候,由於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