DELPHI 多线程,API实现

DELPHI 多线程(API实现):

首先看下构造函数:(会自动销毁)

function CreateThread(

lpThreadAttributes: Pointer; {安全设置} {一般为Nil}

dwStackSize: DWORD; {堆栈大小} {0为默认大小}

lpStartAddress: TFNThreadStartRoutine; {入口函数} { 例:@MyFun}

lpParameter: Pointer; {函数参数}{入口函数的参数}{@参数}

dwCreationFlags: DWORD; {启动选项} {有两个值,0时立即执行入口函数,CREATE_SUSPENDED,挂起等待。可用 ResumeThread(句柄) 函数是恢复线程的运行; 可用 SuspendThread(句柄) 再次挂起线程.}

var lpThreadId: DWORD {输出线程 ID } {输入你的接收句柄变量}

): 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高。