delphi 線程教學第一節:初識多線程


第一節:初識多線程
 
1.為什么要學習多線程編程?
 
多線程(多個線程同時運行)編程,亦可稱之為異步編程。
有了多線程,主界面才不會因為耗時代碼而造成“假死“狀態。
有了多線程,才能使多個任務同時執行,最大化利用CPU資源,提高效率。
在安卓編程中,要求必須是多線程,主界面中的代碼只要耗時幾秒鍾,就會觸發 ANR 錯誤。
多線程編程才是 工作中的常態多線程是必須掌握的!越早越好!
 
2.網絡上 delphi 多線程 Demo 的誤區
 
采用 API 來實現多線程。難度太高,尤其是用指針來傳參數,不適合初學者。
用訪問界面來舉例,出發點就錯了。多線程最不擅長的就是操作UI。
網上流行的 demo 就是弄個大循環,再來一個  TextOut 輸出。
結果又不得不加上 canvas.Lock, 真是夠折騰。
 
3.主線程的定義
 
假設,一個EXE程序,擁有一個 FrmMain (TForm)。
FrmMain 上面有一個 Button1 (TButton) ,一個Edit1 (TEdit)以及一個 Timer1 (TTimer) 。
那么,我們通常把界面(UI)定義為主線程,即 FrmMain 就是主線程。
Button1 的 OnClick 事件中的代碼運行於主線程時空。(本教程均統一定義 線程時空一詞)
使用者在 Edit1 中的輸入操作也是主線程時空。
Timer1 的 OnTimer 事件中的代碼也運行於主線程時空。
請注意:初學者最容易把 OnTimer 事件誤認為是多線程時空。
 
4.普通編程與多線程編程的區別
 
// 普通編程
function  Accumulate(num: integer ): integer ;
var
    i: integer ;
begin
    result:= 0 ;
    if  num< 1  then  exit;
    for  i:= 1  to  num  do
       result:=result+i;
end ;
// 在 Button1 的 OnClick 事件中編寫如下代碼:
var
    n,Total: integer ;
begin
    n:= 100 ;
    Total:=Accumelate(n);
    // 等待計算結果,假設計算需要5分鍾,此處就得等待5分鍾。
    // 這5分鍾內,界面是無法訪問的,是假死的。
    // 計算完成,得到結果 Total=5050;
    DoSomeThing;  //接着執行此句。
end ;
 
// 多線程編程,此為計算線程類
unit  uAccumulation;
interface
uses
   Classes;
type
   TAccumulationThread =  class ;
   TOnAccumulated =  procedure (Sender: TAccumulationThread)  of  object ;
   TAccumulationThread =  class (TThread)
   protected
     procedure  Execute; override;
   public
     Num:  integer ;
     Total:  integer ;
     OnAccumulated: TOnAccumulated;
   end ;
 
implementation
 
procedure  TAccumulationThread . Execute;
var
   i:  integer ;
begin
   inherited ;
   Total :=  0 ;
   if  Num >  0  then
   begin
     for  i :=  1  to  Num  do
       Total := Total + i
   end ;
   // 當計算完成后,就調用  OnAccumulated 通知調用者
   if  Assigned(OnAccumulated)  then
     OnAccumulated(self);
end ;
end .
 
寫代碼請用英語命名,用正確的單詞,時態。切記,非常重要!
 
// 調用多線程
// 在FrmMain 中定義 OnAccumulated 事件函數
Procedure  TFrmMain . OnAccumulated(Sender:TAccumulationThread);
var
    sum: integer ;
begin
    // 當計算完成時,計算線程就調用本事件函數。
    // 我們在這里就得到了計算結果
    sum:=Sender . Total;
    // 因為這里是線程時空,不能直接把 sum 的值顯示到界面上。
    // 如何正確顯示,將下一章節中講解。
end ;
 
// 在Button1 的OnClick 事件中編寫下面的代碼
var
    thd:TAccumulationThread;
begin
    // 此處為主線程時空。
    thd:=TAccumuationThread . Create( true );
    thd . OnAccumulated=Self . OnAccumulated;  // Self 指是 FrmMain.
    thd . Num:= 100 ;
    thd . Start;  //啟動線程,在線程時空中執行 Execute 中的代碼。
    //  start 立即返回並執行下一條代碼 DoSomeThing;
    //  此時,就有兩個線程在同時執行。
    //  1.主線程,也就是此處運行的時代碼。
    //  2.計算線程,也就是 Execute 中的代碼,這些代碼此時運行於多線程時空。
    //  由於是兩個線程並行在執行,故此處 DoSomeThing 馬上可以執行。
    //  界面也不會假死
    DoSomeThing;
end ;
 
通過比較,似乎看出多線程要寫更多的代碼?要用事件來傳遞結果來給調用者?
其實都不然,這兩點均是面向對象(OO)寫法,與線程類無關。
最大的不同是: 異步執行,把耗時的計算任務放了入另一個線程時空!
 
多線程帶來了效率,同時也帶來了更多的麻煩。欲知后事如何,且聽下回分解。
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM