程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 多線程技術在Delphi數據庫編程中應用

多線程技術在Delphi數據庫編程中應用

編輯:Delphi

引言

在傳統上,並發多任務的實現采用的是在操作系統級運行多個進程,由操作系統按照一定的策略(優先級、循環等),調度各個進程的執行,以最大限度的利用計算機的各種資源。在這種實現方法中最基本的調度單位是操作系統級上的進程。由於各個進程擁有自己獨立的運行環境(寄存器和地址空間等)。進程與進程之間的耦合關系差,並發性粒度過於粗糙,並發實現也不太容易。所以,除非特殊需要,一般的應用設計都不采用這種技術。

為了克服這些問題,近年來逐步發展了並發多線程的程序設計技術。從並發Ada、並發C等各種並發多任務的程序設計語言(這些語言中采用的雖然不是線程這個術語,但其基本思想是一樣的),到Mach、Chorus、Solaris System等各種采用了線程技術的系統,多線程技術得到了迅速發展和日益廣泛的應用。IEEE也推出了有關多線程程序設計的標准POSIX1003.4a。特別是在Window NT和Windows 98等流行操作系統中,采用了線程作為基本的調度單位,其API中也提供了有關線程操作的用戶程序接口。所有這些無疑都會促進多線程技術在程序設計中被日益廣泛的采用。

多線程技術的概念

所謂線程(或稱線索,thread),指程序中的以單一的順序控制流。線程按順序執行,即在一個線程中,一個時刻只能由一個執行點。顯然,按傳統方法設計的程序,無論是單道執行的程序,還是由多個進程並發執行的多道程序,就每個程序本身而言,都是由單線程組成的。

多線程程序設計,就是使單個程序中包含並發執行的多個線程。當多線程程序執行時,在該程序對應的進程中就有多個控制流在同時運行,即具有並發執行的多個線程。在一個進程中包含並發執行的多個控制流,而不是把多個控制流一一分散在多個進程中,這是多線程程序設計與並發多進程程序設計截然不同之處。這就決定了二者之間雖然在概念上有許多相通之處,但實現方法則是完全不同。

\
圖1 進程之間的關系
\
圖2 線程之間的關系

圖1和圖2分別示意了把一個任務按兩個並發進程和兩個並發線程分解後的情況。比較這兩張圖中進程與進程之間、線程與線程之間的關系可以看出,進程之間的關系比較疏遠,各個進程是在自己獨有的地址空間內執行,不但寄存器和堆棧是獨有的,動態數據堆、靜態數據區和程序代碼也相互獨立。而線程之間的關系則要緊密的多。雖然各線程為保持自己的控制流而獨有寄存器和堆棧,但由於各線程從屬於同一進程,它們共享同一地址空間,所以動態堆、靜態數據區及程序代碼則是各線程共有的。

許多多任務操作系統限制用戶能擁有的最多進程數目,如很多Unix版本的典型值為20個左右,這對許多並發應用來說遠遠不夠。而對多線程技術來說,不存在這樣的數目限額。

多線程程序設計

線程是系統調度的基本單位,是CPU的一條執行路徑。一個應用程序實例至少有一個線程,即程序的基本線程或主線程。用戶可以根據需要同時創建若干個線程,讓一個程序在同一時刻運行多個線路。線程間獨立運行,每個線程都輪流占用CPU的運行時間和資源,即將CPU的時間分片,每一個時間片給不同的線程使用。這樣,操作系統將不斷的將線程掛起、喚醒、再掛起、再喚醒,直至完成整個任務。

當程序在運行時,線程被加載到內存中等待執行。每個線程都可能包含該應用程序的數據、代碼或者其他操作系統的資源。一個線程執行程序的一部分,所有線程都能夠訪問進程的全局變量。

一個采用多線程的應用程序允許同一程序的多個部分同時執行,為程序賦予了並行特性,因而可以執行某些實時性或隨機性很強的操作,提高對CPU的利用率,加快信息處理速度。

1、線程的創建

筆者利用Delphi語言進行了程序的開發和編寫, 該語言的優點之一是它有一整套線程同步方法,可以很方便地使用。

一個進程的主線程是由操作系統自動生成,如果要讓一個主線程創建額外的線程,在WinAPI中,可以調用CreateThread來完成。在Delphi中,所有的線程類可以從TThread類派生得到,如下:

type
OptimizeThread = class(TThread)
private
{ Private declarations }
DocExec:TADOCommand;
CaseID:Integer; //優化方案代碼
protected
procedure Execute; override;
procedure DoAnalyse;virtual;abstract;
end;
這樣,就從線程基類TThread派生了一個自己的OptimizeThread類,並在此類中添加了新的變量和方法。然後,用戶還需要從OptimizeThread類中派生出一個可供使用的線程對象,如下:

ScheOptimizeThread = class (OptimizeThread)
private
count :integer; //記錄航班的分組
protected
procedure DoAnalyse;override;
public
constructor Create(Exec:TADOCommand;CaseID,count:Integer);
end;

2、線程的掛起和恢復
 
當線程被掛起時,CPU不分配時間片給該線程,線程停止在掛起命令發出時的代碼處,直到被允許繼續進行。想要掛起線程只要調用線程的suspend方法,或者設置線程對象的suspended為True。若要喚醒線程,則只要調用線程的resume方法,或者設置線程對象的suspended為False即可。

3、線程的終止

當線程從Execute()退出時,線程終止,觸發OnTerminate事件,從而清除線程對象。也可以在線程運行過程中,由其他線程控制該線程的退出,這時需要調用線程對象的Terminate方法,並設置該線程對象的Terminate屬性為True。

用多線程實現航班優化編排

航班優化編排考慮的因素多,涉及到的航班數據量大,分析、優化過程較復雜,需要進行大量計算, 同時產生大量中間數據,考慮到各航班之間可以獨立進行分析,我們采取了多線程方法來提高優化速度。

預先將航班分成了三組,用三個線程同時實現。

首先定義了OptimizeThread,並由OptimizeThread派生出ScheOptimizeThread,再分別對OptimizeThread、ScheOptimizeThread中的方法進行定義。

{ OptimizeThread }
procedure OptimizeThread.Execute;
begin
{ Place thread code here }
DoAnalyse;
end;
constructor ScheOptimizeThread.Create(Exec:TADOCommand;CaseID,count:Integer);
begin
docExec:=Exec;
self.CaseID:=CaseID;
self.Sche:=count;
FreeOnTerminate :=True;//線程終止時自動刪除對象
inherited Create(False);
end;

procedure ScheOptimizeThread.DoAnalyse;
begin
docExec.CommandText:=’exec threadtest ’+InttoStr(CaseID)+’ ,’+InttoStr(count);
// 航班優化編排的具體過程,涉及到大量的數據處理,如果把這些數據都調到客戶端,再
// 進行計算,將會增加網絡流量,浪費執行時間,因此在系統中,我們用存儲過程“threadtest”
// 實現,將與數據關系密切的計算直接放在數據所在的節點,計算完畢直接返回結果。
docExec.Execute;
end;
end.
在主程序中可以直接調用

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved