DELPHI 多線程(API實現)

DELPHI 多線程(API實現):安全

首先看下構造函數:(會自動銷燬)多線程

function CreateThread(ide

  lpThreadAttributes: Pointer;           {安全設置}   {通常爲Nil}函數

  dwStackSize: DWORD;                    {堆棧大小} {0爲默認大小}spa

  lpStartAddress: TFNThreadStartRoutine; {入口函數} { 例:@MyFun}線程

  lpParameter: Pointer;                  {函數參數}{入口函數的參數}{@參數}指針

  dwCreationFlags: DWORD;                {啓動選項}  {有兩個值,0時當即執行入口函數,CREATE_SUSPENDED,掛起等待。可用 ResumeThread(句柄) 函數是恢復線程的運行; 可用 SuspendThread(句柄) 再次掛起線程.}code

  var lpThreadId: DWORD                  {輸出線程 ID } {輸入你的接收句柄變量}orm

): THandle; stdcall;                     {返回線程句柄}對象

例子:

 1 unit Unit1;
 2 
 3 interface
 4 
 5 uses
 6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 7   Dialogs, StdCtrls;
 8 
 9 type
10   TForm1 = class(TForm)
11     btn1: TButton;
12     btn2: TButton;
13     procedure btn1Click(Sender: TObject);
14     procedure btn2Click(Sender: TObject);
15   private
16     { Private declarations }
17   public
18     { Public declarations }
19   end;
20 
21 var
22   Form1: TForm1;
23 
24 implementation
25 
26 {$R *.dfm}
27 
28 function MyFun(p:Pointer):integer;stdcall; {工做線程調入函數,stdcall用於多個線程排序以及系統級別調用加此關鍵字}
29 var
30   i:integer;
31 begin
32   for i := 0 to 500000 do    
33   begin
34     with Form1.Canvas do
35     begin
36       Lock;
37       TextOut(50,10,IntToStr(i)); {50和10是座標X和Y}
38       Unlock;
39       Application.ProcessMessages;
40     end;
41   end;
42 end;
43 
44 procedure TForm1.btn1Click(Sender: TObject);{主線程}
45 var
46   i:integer;
47 begin
48   for i := 0 to 500000 do  
49   begin
50     with Form1.Canvas do
51     begin
52       Lock;
53       TextOut(10,10,IntToStr(i)); {10和10是座標X和Y}
54       Unlock;
55       Application.ProcessMessages;{加上去纔在計數時不會卡住,拖動窗體時,計數會有停頓}
56     end;
57   end;
58 
59 end;
60 
61 procedure TForm1.btn2Click(Sender: TObject);{工做線程,拖動窗口時計數不會停頓,由於和主線程分開工做了}
62 var
63   ID:THandle; {用於接收線程返回句柄,也能夠用DWORD}
64 begin
65   CreateThread(nil,0,@MyFun,nil,0,ID);  {API建立線程}
66 end;
67 
68 end.

CriticalSection(臨界區):

 1 unit Unit1;
 2 
 3 interface
 4 
 5 uses
 6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 7   Dialogs, StdCtrls;
 8 
 9 type
10   TForm1 = class(TForm)
11     lst1: TListBox;
12     btn1: TButton;
13     procedure btn1Click(Sender: TObject);
14     procedure FormDestroy(Sender: TObject);
15   private
16     { Private declarations }
17   public
18     { Public declarations }
19   end;
20 
21 var
22   Form1: TForm1;
23 
24 implementation
25 
26 {$R *.dfm}
27 
28 var
29   CS:TRTLCriticalSection; {聲明臨界}
30 
31 function MyFun(p:Pointer):integer;stdcall;
32 var
33   i:integer;
34 begin
35   EnterCriticalSection(CS);  {我要用了,別人先別用}
36   for i := 0 to 100 - 1 do
37   begin
38     Form1.lst1.Items.Add(IntToStr(i));
39   end;
40   LeaveCriticalSection(CS);  {我用完了,別能夠用了}
41 
42 end;
43 
44 procedure TForm1.btn1Click(Sender: TObject);
45 var
46   ID:THandle;
47 begin
48   InitializeCriticalSection(CS); {初始化臨界}
49   CreateThread(nil,0,@MyFun,nil,0,ID);
50   CreateThread(nil,0,@MyFun,nil,0,ID);
51   CreateThread(nil,0,@MyFun,nil,0,ID);
52 end;
53 
54 procedure TForm1.FormDestroy(Sender: TObject);
55 begin
56   DeleteCriticalSection(CS);  {刪除臨界}
57 end;
58 
59 end.

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

先說明等待函數(後面要配套使用):

function WaitForSingleObject(
hHandle: THandle; {要等待的對象句柄}
dwMilliseconds: DWORD {等待的時間, 單位是毫秒}
): DWORD; stdcall; {返回值以下:}

WAIT_OBJECT_0 {等着了, 本例中是: 等的那個進程終於結束了}
WAIT_TIMEOUT {等過了點(你指定的時間), 也沒等着}
WAIT_ABANDONED {好不容易等着了, 但人家仍是不讓咱執行; 這通常是互斥對象}

//WaitForSingleObject 的第二個參數通常給常數值 INFINITE, 表示一直等下去, 死等.

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Mutex (互斥對象)

要理解的函數有:

function CreateMutex(
lpMutexAttributes: PSecurityAttributes; {安全參數,默認真nil}
bInitialOwner: BOOL; {是否讓建立者(此例中是主線程)擁有該互斥對象}{通常爲False}
lpName: PWideChar {能夠給此互斥對象取個名字, 若是不要名字可賦值爲 nil}
): THandle;

 1 unit Unit1;
 2 
 3 interface
 4 
 5 uses
 6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 7   Dialogs, StdCtrls;
 8 
 9 type
10   TForm1 = class(TForm)
11     btn1: TButton;
12     procedure btn1Click(Sender: TObject);
13     procedure FormDestroy(Sender: TObject);
14   private
15     { Private declarations }
16   public
17     { Public declarations }
18   end;
19 
20 var
21   Form1: TForm1;
22 
23 implementation
24 
25 {$R *.dfm}
26 
27 var
28   hMutex:THandle; {聲明互斥變量句柄}
29   f:Integer;      {用於協調輸出位置的變量}
30 
31 function MyFun(p:Pointer):Integer;stdcall;
32 var
33   i,y:integer;
34 begin
35   Inc(f);  {步進f}
36   y:=20*f;
37   if WaitForSingleObject(hMutex,INFINITE)=WAIT_OBJECT_0 then   {等待函數}
38   begin
39     for i := 0 to 500 do
40     begin
41       with Form1.Canvas do
42       begin
43         Lock;
44         TextOut(10,Y,IntToStr(i));
45         Unlock;
46         sleep(1); {太快怕忙不過來}
47       end;
48     end;
49     ReleaseMutex(hMutex);
50   end;
51 end;  
52 
53 
54 procedure TForm1.btn1Click(Sender: TObject);
55 var
56   ID:THandle;
57 begin
58   f:=0; {初始化f爲0}
59   Repaint; {重畫}
60   CloseHandle(hMutex); {先關閉句柄}
61   hMutex:=CreateMutex(nil,False,nil);  {建立互斥體}
62   CreateThread(nil,0,@MyFun,nil,0,ID);
63   CreateThread(nil,0,@MyFun,nil,0,ID);
64   CreateThread(nil,0,@MyFun,nil,0,ID);
65   CreateThread(nil,0,@MyFun,nil,0,ID);
66 end;
67 
68 procedure TForm1.FormDestroy(Sender: TObject);
69 begin
70   CloseHandle(hMutex);  {關閉句柄}
71 end;
72 
73 end.

Semaphore(信號或叫信號量)

要理解的函數:

CreateSemaphore(安全設置, 初始信號數, 信號總數, 信號名稱) 創建信號對象;
參數四: 和 Mutex 同樣, 它能夠有個名稱, 也能夠沒有, 本例就沒有要名稱(nil); 有名稱的通常用於跨進程.
參數三: 信號總數, 是 Semaphore 最大處理能力, 就像銀行一共有多少個業務窗口同樣; 
參數二: 初始信號數, 這就像銀行的業務窗口不少, 但打開了幾個可不必定, 若是沒打開和沒有同樣;{本例用個EDIT輸入數量,每次釋放後又進行一樣數量}
參數一: 安全設置和前面同樣, 使用默認(nil)便可.

ReleaseSemaphore(接受信號量句柄,1[接收多少個信號] , nil[通常爲空,若是是指針能夠接受到此時共閒置了多少個信號量]);

 1 unit Unit1;
 2 
 3 interface
 4 
 5 uses
 6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 7   Dialogs, StdCtrls;
 8 
 9 type
10   TForm1 = class(TForm)
11     btn1: TButton;
12     edt1: TEdit;
13     procedure btn1Click(Sender: TObject);
14     procedure FormDestroy(Sender: TObject);
15     procedure btn1KeyPress(Sender: TObject; var Key: Char);
16   private
17     { Private declarations }
18   public
19     { Public declarations }
20   end;
21 
22 var
23   Form1: TForm1;
24 
25 implementation
26 
27 {$R *.dfm}
28 
29 var
30   hsmaphore:THandle; {信號量句柄}
31   f:Integer;         {協調輸出的變量}
32 
33 function MyFun(p:Pointer):integer;
34 var
35   i,y:integer;
36 begin
37   Inc(f);
38   y:=20*f;
39   if WaitForSingleObject(hsmaphore,INFINITE)=WAIT_OBJECT_0 then
40   begin
41     for i := 0 to 500 do
42     begin
43       with Form1,Canvas do
44       begin
45         Lock;
46         TextOut(10,y,IntToStr(i));
47         Unlock;
48         Sleep(1);
49       end;
50     end;
51     ReleaseSemaphore(hsmaphore,1,nil); {釋放函數}
52   end;
53   Result:=0;
54 end;
55 
56 procedure TForm1.btn1Click(Sender: TObject);
57 var
58   ID:DWORD;
59 begin
60   CloseHandle(hsmaphore);  {先關閉句柄}
61   hsmaphore:=CreateSemaphore(nil,StrToInt(edt1.Text),5,nil); {建立句柄}
62   CreateThread(nil,0,@MyFun,nil,0,ID);   {建立線程}
63   CreateThread(nil,0,@MyFun,nil,0,ID);
64   CreateThread(nil,0,@MyFun,nil,0,ID);
65   CreateThread(nil,0,@MyFun,nil,0,ID);
66   CreateThread(nil,0,@MyFun,nil,0,ID);
67 end;
68 
69 procedure TForm1.btn1KeyPress(Sender: TObject; var Key: Char);
70 begin
71   if not (Key in ['1'..'5']) then Key:=#0;  {設置只能輸入1到5,而且在控件屬性設置寬度爲1}
72   
73 end;
74 
75 procedure TForm1.FormDestroy(Sender: TObject);
76 begin
77   CloseHandle(hsmaphore);  {關閉句柄}
78 end;
79 
80 end.

Event (事件對象)

function CreateEvent(
lpEventAttributes: PSecurityAttributes; {安全設置}
bManualReset: BOOL; {第一個布爾}
bInitialState: BOOL; {第二個布爾}
lpName: PWideChar {對象名稱}
): THandle; stdcall; {返回對象句柄}

//第一個布爾爲 False 時, 事件對象控制一次後將當即重置(暫停); 爲 True 時可手動暫停.
//第二個布爾爲 False 時, 對象創建後控制爲暫停狀態; True 是可運行狀態.

  1 unit Unit1;
  2 
  3 interface
  4 
  5 uses
  6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7   Dialogs, StdCtrls;
  8 
  9 type
 10   TForm1 = class(TForm)
 11     btn1: TButton;
 12     btn2: TButton;
 13     btn3: TButton;
 14     btn4: TButton;
 15     btn5: TButton;
 16     procedure btn1Click(Sender: TObject);
 17     procedure btn2Click(Sender: TObject);
 18     procedure btn3Click(Sender: TObject);
 19     procedure btn4Click(Sender: TObject);
 20     procedure btn5Click(Sender: TObject);
 21     procedure FormCreate(Sender: TObject);
 22     procedure FormDestroy(Sender: TObject);
 23   private
 24     { Private declarations }
 25   public
 26     { Public declarations }
 27   end;
 28 
 29 var
 30   Form1: TForm1;
 31 
 32 implementation
 33 
 34 {$R *.dfm}
 35 
 36 var
 37   hEvent:THandle;
 38   f:integer;
 39 
 40 function MyFun (p:Pointer):Integer;
 41 var
 42   i,y:integer;
 43 begin
 44   Inc(f);
 45   y:=20*f;
 46   for i := 0 to 200000 do
 47   begin
 48     if WaitForSingleObject(hEvent,INFINITE)=WAIT_OBJECT_0 then
 49     begin
 50       Form1.Canvas.Lock;
 51       Form1.Canvas.TextOut(10,y,IntToStr(i));
 52       Form1.Canvas.Unlock;
 53       
 54     end;
 55   end;
 56   Result:=0;
 57 end;
 58 
 59 procedure TForm1.btn1Click(Sender: TObject);
 60 var
 61   ID:DWORD;
 62 begin
 63   Repaint;  {重畫}
 64   f:=0;
 65   CloseHandle(hEvent);{先關閉線程}
 66   hEvent:=CreateEvent(nil,True,True,nil)  {建立事件}
 67 end;
 68 
 69 procedure TForm1.btn2Click(Sender: TObject);
 70 var
 71   ID:DWORD;
 72 begin
 73   CreateThread(nil,0,@MyFun,nil,0,ID);  {建立線程}
 74 
 75 end;
 76 
 77 procedure TForm1.btn3Click(Sender: TObject);
 78 begin
 79   ResetEvent(hEvent); {暫停,可對當前全部事件相關線程暫停}
 80 end;
 81 
 82 procedure TForm1.btn4Click(Sender: TObject);
 83 begin
 84   SetEvent(hEvent);  {啓動,可對當前全部事件相關線程啓動}
 85 end;
 86 
 87 procedure TForm1.btn5Click(Sender: TObject);
 88 begin
 89   PulseEvent(hEvent); {啓動一次再暫停,可對當前全部事件相關線程}
 90 end;
 91 
 92 procedure TForm1.FormCreate(Sender: TObject);
 93 begin
 94   btn1.Caption := '建立 Event 對象';
 95   btn2.Caption := '建立線程';
 96   btn3.Caption := 'ResetEvent';
 97   btn4.Caption := 'SetEvent';
 98   btn5.Caption := 'PulseEvent';
 99 end;
100 
101 procedure TForm1.FormDestroy(Sender: TObject);
102 begin
103   CloseHandle(hEvent); {關閉事件句柄}
104 end;
105 
106 end.

等待記時器對象:WaitableTimer{比較複雜,可不記,須要使用時查閱}

{它的主要功用相似 TTimer 類,既然有了方便的 TTimer, 何須再使用 WaitableTimer 呢?
由於 WaitableTimer 比 TTimer 精確的多, 它的間隔時間能夠精確到毫秒、它的指定時間甚至是精確到 0.1 毫秒;
而 TTimer 驅動的 WM_TIMER 消息, 是消息隊列中優先級最低的, 也就是再同一時刻 WM_TIMER 消息老是被最後處理.
還有重要的一點 WaitableTimer 能夠跨線程、跨進程使用.}

須要瞭解的函數:

function CreateWaitableTimer(
lpTimerAttributes: PSecurityAttributes; {安全}
bManualReset: BOOL; {True: 可調度多個線程; False: 只調度一個線程}
lpTimerName: PWideChar {名稱}
): THandle; stdcall; {返回句柄}

function SetWaitableTimer(
hTimer: THandle; {句柄} {WaitableTimer 對象的句柄}
var lpDueTime: TLargeInteger; {起始時間} //0爲立刻,另有相對時間如:-3*10000000; {3秒鐘後執行},絕對時間:如:'2016-08-26 10:06:00' 須要轉換
lPeriod: Longint; {間隔時間}
pfnCompletionRoutine: TFNTimerAPCRoutine;{回調函數的指針,不用時爲空} 
lpArgToCompletionRoutine: Pointer; {給回調函數的參數,不用時爲空}
fResume: BOOL {是否喚醒系統}{此值如果 True, 即便系統在屏保或待機狀態, 時間一到線程和系統將都被喚醒!}
): BOOL; stdcall; {}

 

例1:指定多少秒後運行(相對時間):

 1 unit Unit1;
 2 
 3 interface
 4 
 5 uses
 6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 7   Dialogs, StdCtrls;
 8 
 9 type
10   TForm1 = class(TForm)
11     btn1: TButton;
12     procedure btn1Click(Sender: TObject);
13     procedure FormDestroy(Sender: TObject);
14   private
15     { Private declarations }
16   public
17     { Public declarations }
18   end;
19 
20 var
21   Form1: TForm1;
22 
23 implementation
24 
25 {$R *.dfm}
26 
27 var
28   hWaitableTimer:THandle;
29   f:integer;
30 
31 function MyFun(p:Pointer):integer;
32 var
33   i,y:integer;
34 begin
35   inc(f);
36   y:=20*f;
37 
38   if WaitForSingleObject(hWaitableTimer,INFINITE)=WAIT_OBJECT_0 then
39   begin
40     for I := 0 to 1000 do
41     begin
42       Form1.Canvas.Lock;
43       Form1.Canvas.TextOut(10,Y,IntToStr(I));
44       Form1.Canvas.Unlock;
45       Sleep(1);
46     end;
47   end;
48   Result:=0;
49 end;
50 
51 
52 
53 procedure TForm1.btn1Click(Sender: TObject);
54 var
55   DueTimer:Int64;
56   ID:DWORD;
57 begin
58   hWaitableTimer:=CreateWaitableTimer(nil,True,nil); {建立等待計時器,容許多線程同時進行}
59   DueTimer:=-3*10000000; {三秒後執行}
60   SetWaitableTimer(hWaitableTimer,DueTimer,0,nil,nil,False);  {設置計時器開始運行時間}
61 
62   Repaint;
63   f:=0;
64   CreateThread(nil,0,@MyFun,nil,0,ID);
65   CreateThread(nil,0,@MyFun,nil,0,ID);
66   CreateThread(nil,0,@MyFun,nil,0,ID);
67 end;
68 
69 procedure TForm1.FormDestroy(Sender: TObject);
70 begin
71   CloseHandle(hWaitableTimer); {句柄}
72 end;
73 
74 end.

例2:指定一個時間裏運行(絕對時間):

//StrToDateTime -> DateTimeToSystemTime -> SystemTimeToFileTime -> LocalFileTimeToFileTime 時間轉換

 1 unit Unit1;
 2 
 3 interface
 4 
 5 uses
 6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 7   Dialogs, StdCtrls;
 8 
 9 type
10   TForm1 = class(TForm)
11     btn1: TButton;
12     procedure btn1Click(Sender: TObject);
13     procedure FormDestroy(Sender: TObject);
14   private
15     { Private declarations }
16   public
17     { Public declarations }
18   end;
19 
20 var
21   Form1: TForm1;
22 
23 implementation
24 
25 {$R *.dfm}
26 
27 var
28   hWaitableTimer:THandle;
29   f:integer;
30 
31 function MyFun(p:Pointer):integer;
32 var
33   i,y:integer;
34 begin
35   inc(f);
36   y:=20*f;
37 
38   if WaitForSingleObject(hWaitableTimer,INFINITE)=WAIT_OBJECT_0 then
39   begin
40     for I := 0 to 1000 do
41     begin
42       Form1.Canvas.Lock;
43       Form1.Canvas.TextOut(10,Y,IntToStr(I));
44       Form1.Canvas.Unlock;
45       Sleep(1);
46     end;
47   end;
48   Result:=0;
49 end;
50 
51 
52 
53 procedure TForm1.btn1Click(Sender: TObject);
54 const
55   strTime='2016-8-29 14:41:30';
56 var
57   DueTimer:Int64;
58   ID:DWORD;
59   st:TSystemTime;
60   ft,Utc:TFileTime;
61   dt:TDateTime;
62 begin
63   DateTimeToSystemTime(StrToDateTime(strTime), st); {從 TDateTime 到 TSystemTime}
64   SystemTimeToFileTime(st, ft);                     {從 TSystemTime 到 TFileTime}
65   LocalFileTimeToFileTime(ft, UTC);                 {從本地時間到國際標準時間 UTC}
66   DueTimer:= Int64(UTC);                            {函數須要的是 Int64}
67 
68   hWaitableTimer:=CreateWaitableTimer(nil,True,nil); {建立等待計時器,容許多線程同時進行}
69   SetWaitableTimer(hWaitableTimer,DueTimer,0,nil,nil,False);  {設置計時器開始運行時間}
70 
71   Repaint;
72   f:=0;
73   CreateThread(nil,0,@MyFun,nil,0,ID);
74   CreateThread(nil,0,@MyFun,nil,0,ID);
75   CreateThread(nil,0,@MyFun,nil,0,ID);
76 end;
77 
78 procedure TForm1.FormDestroy(Sender: TObject);
79 begin
80   CloseHandle(hWaitableTimer); {關閉句柄}
81 end;
82 
83 end.

 

下面例子須要瞭解如下函數:

function SleepEx(
dwMilliseconds: DWORD; {毫秒數} {INFINITE 表示一直等}
bAlertable: BOOL {布爾值}
): DWORD; stdcall;

//第一個參數和 Sleep 的那個參數是同樣的, 是線程等待(或叫掛起)的時間, 時間一到無論後面參數如何都會返回.

//第二個參數若是是 False, SleepEx 將不會關照 APC 函數是否入列;
//如果 True, 只要有 APC 函數申請, SleepEx 無論第一個參數如何都會把 APC 推入隊列並隨 APC 函數一塊兒返回.

//注意: SetWaitableTimer 和 SleepEx 必須在同一個線程才能夠.

procedure TimerAPCProc(lpArgToCompletionRoutine: Pointer;dwTimerLowValue: DWORD;dwTimerHighValue: DWORD); stdcall;
//系統定義給SetWaitableTimer第一個回調函數指針的格式函數{名字能夠變,格式和類型不能變。}

 

例3:窗口標題自增數字

本例在SetWaitableTimer使用TimerAPCProc回調函數,但不使用回調函數的參數

 1 unit Unit1;
 2 
 3 interface
 4 
 5 uses
 6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 7   Dialogs, StdCtrls;
 8 
 9 type
10   TForm1 = class(TForm)
11     btn1: TButton;
12     btn2: TButton;
13     procedure btn1Click(Sender: TObject);
14     procedure btn2Click(Sender: TObject);
15     procedure FormDestroy(Sender: TObject);
16   private
17     { Private declarations }
18   public
19     { Public declarations }
20   end;
21 
22 var
23   Form1: TForm1;
24 
25 implementation
26 
27 {$R *.dfm}
28 
29 var
30   hTimer:THandle;
31 
32 procedure TimerAPCProc(APointer:Pointer;dwTimerLowValue:DWORD;dwTimerHighValue:DWORD);stdcall;
33 begin
34   Form1.Text:=IntToStr(StrToIntDef(Form1.Text,0)+1);
35   SleepEx(INFINITE,True);     {在回調參數里加這一句,會不斷的循環}
36 end;
37 
38 function MyFun(p:Pointer):integer;stdcall;
39 var
40   DueTime:Int64;
41 begin
42   DueTime:=0;
43   {SetWaitableTimer 必須與 SleepEx 在同一線程}
44   if SetWaitableTimer(hTimer,DueTime,1000,@TimerAPCProc,nil,False) then  //使用了APC回調函數,回調函數的參數此例沒有
45   begin
46     SleepEx(INFINITE,True);
47   end;
48   Result:=0;
49 end;
50 
51 procedure TForm1.btn1Click(Sender: TObject);
52 var
53   ID:DWORD;
54 begin
55   CloseHandle(hTimer);
56   hTimer:=CreateWaitableTimer(nil,True,nil); {創建定時器}
57   CreateThread(nil,0,@MyFun,nil,0,ID);    {建立線程}
58 end;
59 
60 procedure TForm1.btn2Click(Sender: TObject);
61 begin
62   CancelWaitableTimer(hTimer);{取消定時器}
63 end;
64 
65 procedure TForm1.FormDestroy(Sender: TObject);
66 begin
67   CloseHandle(hTimer);  {關閉句柄}
68 end;
69 
70 end.

 

例4:在窗口標題上顯示時間並自增計時

本例利用APC回調參數的第二個,第三個參數值得到時間並轉換輸出

//參數高低位時間>>合併成TFileTime(世界標準計時)>>LocalFileTime本地時間>>SystemTime系統時間>>Datetime

 1 unit Unit1;
 2 
 3 interface
 4 
 5 uses
 6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 7   Dialogs, StdCtrls;
 8 
 9 type
10   TForm1 = class(TForm)
11     btn1: TButton;
12     btn2: TButton;
13     procedure btn1Click(Sender: TObject);
14     procedure btn2Click(Sender: TObject);
15     procedure FormDestroy(Sender: TObject);
16   private
17     { Private declarations }
18   public
19     { Public declarations }
20   end;
21 
22 var
23   Form1: TForm1;
24 
25 implementation
26 
27 {$R *.dfm}
28 
29 var
30   hTimer:THandle;
31 
32 procedure TimerAPCProc(APointer:Pointer;dwTimerLowValue:DWORD;dwTimerHighValue:DWORD);stdcall;
33 var
34   UTCFileTime,LocalFileTime:TFileTime;
35   SystemTime:TSystemTime;
36   DateTime:TDateTime;
37 begin
38    {把 dwTimerLowValue 與 dwTimerHighValue 和併爲一個 TFileTime 格式的時間}
39   UTCFileTime.dwLowDateTime := dwTimerLowValue;
40   UTCFileTime.dwHighDateTime := dwTimerHighValue;
41 
42   FileTimeToLocalFileTime(UTCFileTime, LocalFileTime); {從世界標準計時到本地時間}
43   FileTimeToSystemTime(LocalFileTime, SystemTime);     {轉到系統格式時間}
44   DateTime := SystemTimeToDateTime(SystemTime);        {再轉到 TDateTime}
45 
46   Form1.Text:=DateTimeToStr(DateTime);
47   SleepEx(INFINITE,True);     {在回調參數里加這一句,會不斷的循環}
48 end;
49 
50 function MyFun(p:Pointer):integer;stdcall;
51 var
52   DueTime:Int64;
53 begin
54   DueTime:=0;
55   {SetWaitableTimer 必須與 SleepEx 在同一線程}
56   if SetWaitableTimer(hTimer,DueTime,1000,@TimerAPCProc,nil,False) then  //使用了APC回調函數
57   begin
58     SleepEx(INFINITE,True);
59   end;
60   Result:=0;
61 end;
62 
63 procedure TForm1.btn1Click(Sender: TObject);
64 var
65   ID:DWORD;
66 begin
67   CloseHandle(hTimer);
68   hTimer:=CreateWaitableTimer(nil,True,nil); {創建定時器}
69   CreateThread(nil,0,@MyFun,nil,0,ID);    {建立線程}
70 end;
71 
72 procedure TForm1.btn2Click(Sender: TObject);
73 begin
74   CancelWaitableTimer(hTimer);{取消定時器}
75 end;
76 
77 procedure TForm1.FormDestroy(Sender: TObject);
78 begin
79   CloseHandle(hTimer);  {關閉句柄}
80 end;
81 
82 end.

 

例5:根據鼠標移動事件獲得坐票在窗體上出現若干個時間計時

本例利用APC回調參數的第一個指針傳遞座標

 1 unit Unit1;
 2 
 3 interface
 4 
 5 uses
 6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 7   Dialogs, StdCtrls;
 8 
 9 type
10   TForm1 = class(TForm)
11     procedure FormDestroy(Sender: TObject);
12     procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
13       Shift: TShiftState; X, Y: Integer);
14   private
15     { Private declarations }
16   public
17     { Public declarations }
18   end;
19 
20 var
21   Form1: TForm1;
22 
23 implementation
24 
25 {$R *.dfm}
26 
27 var
28   hTimer:THandle; {等待計時器句柄}
29   pt:TPoint;      {用來傳遞座標}
30 
31 procedure TimerAPCProc(APointer:Pointer;dwTimerLowValue:DWORD;dwTimerHighValue:DWORD);stdcall;
32 var
33   UTCFileTime,LocalFileTime:TFileTime;
34   SystemTime:TSystemTime;
35   DateTime:TDateTime;
36   pt2:TPoint;
37 begin
38    {把 dwTimerLowValue 與 dwTimerHighValue 和併爲一個 TFileTime 格式的時間}
39   UTCFileTime.dwLowDateTime := dwTimerLowValue;
40   UTCFileTime.dwHighDateTime := dwTimerHighValue;
41 
42   FileTimeToLocalFileTime(UTCFileTime, LocalFileTime); {從世界標準計時到本地時間}
43   FileTimeToSystemTime(LocalFileTime, SystemTime);     {轉到系統格式時間}
44   DateTime := SystemTimeToDateTime(SystemTime);        {再轉到 TDateTime}
45 
46   pt2:=PPoint(APointer)^; {接受第一個指針參數座標 }
47   Form1.Canvas.Lock;
48   Form1.Canvas.TextOut(pt2.x,pt2.Y,DateTimeToStr(DateTime)); {取XY爲座標}
49   Form1.Canvas.Unlock;
50 
51   SleepEx(INFINITE,True);  {此句可作循環}
52 end;
53 
54 function MyFun(p:Pointer):integer;stdcall;
55 var
56   DueTime:Int64;
57 begin
58   DueTime:=0;
59   {SetWaitableTimer 必須與 SleepEx 在同一線程}
60   if SetWaitableTimer(hTimer,DueTime,1000,@TimerAPCProc,@pt,False) then  //使用了APC回調函數
61   begin
62     SleepEx(INFINITE,True);  {此句用作循環}
63   end;
64   Result:=0;
65 end;
66 
67 
68 procedure TForm1.FormDestroy(Sender: TObject);
69 begin
70   CloseHandle(hTimer);  {關閉句柄}
71 end;
72 
73 
74 
75 procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
76   Shift: TShiftState; X, Y: Integer);
77 var
78   ID:DWORD;
79 begin
80   pt:=Point(x,y); {把XY坐票給pt}
81   if hTimer = 0 then hTimer:=CreateWaitableTimer(nil,True,nil);
82   CreateThread(nil,0,@MyFun,nil,0,ID);
83 end;
84 
85 end.

 

總結:

1.主線程作相似循環輸出佔用資源會容易卡住,使用Application.ProcessMessages雖然能夠解決卡頓,但是卻會讓循環停下。

2.當須要用多線程安排時,就要用到臨界,互斥,信號量,事件,等待計時器(較複雜),如下根據需求做說明:

   臨界:多個線程,一個一個進,用完一個再繼續下一個。

   互斥:接力棒,誰拿到是誰的。(看等待函數放哪和釋放語句放哪,可多個搶着進行,也可一個個運行。)

   信號量:可設置線程總數和先運行的數量。

   事件:可對事件相關的線程進行暫停,開始,步進後暫停。

   等待計時器:可根據須要設定爲立刻(0),相對時間,絕對時間運行;另外APC隊伍調度級別高,時間精確度也比TTimer高。

相關文章
相關標籤/搜索