Delphi多线程编程16多线程同步之 Waitab.docx

上传人:b****4 文档编号:24650300 上传时间:2023-05-29 格式:DOCX 页数:11 大小:54.29KB
下载 相关 举报
Delphi多线程编程16多线程同步之 Waitab.docx_第1页
第1页 / 共11页
Delphi多线程编程16多线程同步之 Waitab.docx_第2页
第2页 / 共11页
Delphi多线程编程16多线程同步之 Waitab.docx_第3页
第3页 / 共11页
Delphi多线程编程16多线程同步之 Waitab.docx_第4页
第4页 / 共11页
Delphi多线程编程16多线程同步之 Waitab.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

Delphi多线程编程16多线程同步之 Waitab.docx

《Delphi多线程编程16多线程同步之 Waitab.docx》由会员分享,可在线阅读,更多相关《Delphi多线程编程16多线程同步之 Waitab.docx(11页珍藏版)》请在冰豆网上搜索。

Delphi多线程编程16多线程同步之 Waitab.docx

Delphi多线程编程16多线程同步之Waitab

想过没有?

WaitableTimer是在"定时等待",前面例子中的WaitForSingleObject等待函数"也在等待",这就"双重等待"了,这不好,太浪费资源.

其实作为同步工具,前面的几种方法(事件、信号、临界区)基本够用了;WaitableTimer的作用并不是为了重复前面的功能,它的主要功用类似TTimer类;譬如每隔多长时间执行一段代码、或在指定的时间去执行一段代码.

既然有了方便的TTimer,何必再使用WaitableTimer呢?

因为WaitableTimer比TTimer精确的多,它的间隔时间可以精确到毫秒、它的指定时间甚至是精确到0.1毫秒;

而TTimer驱动的WM_TIMER消息,是消息队列中优先级最低的,也就是再同一时刻WM_TIMER消息总是被最后处理.

还有重要的一点WaitableTimer可以跨线程、跨进程使用.

继续探讨一个重要的点:

很多时候为了让线程不冲突,线程也在等待,既然有等待,那WaitableTimer非常精确的定时又有什么价值呢?

对这个问题的思考,可以让我们很好地理解APC函数.

SetWaitableTimer有个回调函数(其实是个过程),Windows要求它的格式是:

procedureTimerAPCProc(

lpArgToCompletionRoutine:

Pointer;

dwTimerLowValue:

DWORD;

dwTimerHighValue:

DWORD

);stdcall;

函数名中有APC的字样,指示这是个APC函数(尽管这个名称无所谓,这是官方命名),那什么是APC函数?

APC(AsyncroneusProcedureCall):

异步过程调用.

原来每个线程除了有单独的消息队列,还有一个APC队列(等待执行的APC函数);如果线程发现APC队列中有情况,马上会跳过去执行,执行完毕后才回来接着处理消息队列.

说起来麻烦,使用的时候只按上面格式传入函数指针就行;不过能进入APC队列的回调函数和其他回调函数还有一个很大的不同:

SetWaitableTimer按格式调用APC函数后,需要在"当前线程"见到一个"等待",此APC函数才可以进入队列.

这好像很费解,例说一下:

APC队列有那么高的优先级,因为对资源的优先使用会对其他消息有很大的影响,肯定不能随便进入,这是不是像生活中的贵宾席或贵宾通道?

也就是说,要进入APC队列只有SetWaitableTimer的调用还不够,还要通过"等待函数"介绍一下.

WaitForSingleObject吗?

不是,它不够级别;下面是Windows认可的、可以介绍APC入列的等待函数:

SleepEx();

WaitForSingleObjectEx();

WaitForMultipleObjectsEx();

MsgWaitForMultipleObjectsEx();

SignalObjectAndWait();

为什么是用等待函数来把关?

因为上面几个等待函数也可以等待是否有APC函数想入列.

上面给出的几个等待函数,就SleepEx的参数最少,先用它吧:

functionSleepEx(

dwMilliseconds:

DWORD;{毫秒数}

bAlertable:

BOOL{布尔值}

):

DWORD;stdcall;

//第一个参数和Sleep的那个参数是一样的,是线程等待(或叫挂起)的时间,时间一到不管后面参数如何都会返回.

//第二个参数如果是False,SleepEx将不会关照APC函数是否入列;

//若是True,只要有APC函数申请,SleepEx不管第一个参数如何都会把APC推入队列并随APC函数一起返回.

//注意:

SetWaitableTimer和SleepEx必须在同一个线程才可以.

本例效果图:

代码文件:

unitUnit1;

interface

uses

Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,

Dialogs,ExtCtrls,StdCtrls;

type

TForm1=class(TForm)

Button1:

TButton;

procedureButton1Click(Sender:

TObject);

procedureFormDestroy(Sender:

TObject);

end;

var

Form1:

TForm1;

implementation

{$R*.dfm}

var

hTimer:

THandle;

{APC函数(过程),函数名和参数名可以不同,格式必须如此}

procedureTimerAPCProc(lpArgToCompletionRoutine:

Pointer;dwTimerLowValue:

DWORD;

dwTimerHighValue:

DWORD);stdcall;

begin

Form1.Text:

=IntToStr(StrToIntDef(Form1.Text,0)+1);{标题+1}

end;

procedureTForm1.Button1Click(Sender:

TObject);

var

DueTime:

Int64;

begin

hTimer:

=CreateWaitableTimer(nil,True,nil);

DueTime:

=0;

ifSetWaitableTimer(hTimer,DueTime,0,@TimerAPCProc,nil,False)then

begin

SleepEx(INFINITE,True);{INFINITE表示一直等}

end;

end;

procedureTForm1.FormDestroy(Sender:

TObject);

begin

CloseHandle(hTimer);

end;

end.

窗体文件:

objectForm1:

TForm1

Left=0

Top=0

Caption='Form1'

ClientHeight=113

ClientWidth=203

Color=clBtnFace

Font.Charset=DEFAULT_CHARSET

Font.Color=clWindowText

Font.Height=-11

Font.Name='Tahoma'

Font.Style=[]

OldCreateOrder=False

PixelsPerInch=96

TextHeight=13

objectButton1:

TButton

Left=64

Top=48

Width=75

Height=25

Caption='Button1'

TabOrder=0

OnClick=Button1Click

end

end

在上面例子中,每点一次鼠标,那个回调函数才执行一次;作为定时器,如果想让它每秒执行一次怎么弄?

但每一次执行那个APC函数,都得有SleepEx(当然不止它)给送进去,那这样得反复调用SleepEx才可以.

怎么调用,用循环吗?

别说网上能找到的例子我没见到不用循环的(太笨了),就在那个APC函数里调用不就完了.

当然这时一般要设时间间隔的,下面我们将设间隔为1000(1秒).

但接着问题又来了,譬如把代码修改成:

var

hTimer:

THandle;

procedureTimerAPCProc(lpArgToCompletionRoutine:

Pointer;dwTimerLowValue:

DWORD;

dwTimerHighValue:

DWORD);stdcall;

begin

Form1.Text:

=IntToStr(StrToIntDef(Form1.Text,0)+1);

SleepEx(INFINITE,True);{这里再次调用SleepEx}

end;

procedureTForm1.Button1Click(Sender:

TObject);

var

DueTime:

Int64;

begin

hTimer:

=CreateWaitableTimer(nil,True,nil);

DueTime:

=0;

{下面的参数1000表示间隔1秒}

ifSetWaitableTimer(hTimer,DueTime,1000,@TimerAPCProc,nil,False)then

begin

SleepEx(INFINITE,True);

end;

end;

procedureTForm1.FormDestroy(Sender:

TObject);

begin

CloseHandle(hTimer);

end;

任务能完成,但窗体"死"了...怎么办?

嘿,现在学的不是多线程吗?

下面例子中,同时使用了CancelWaitableTimer来取消定时器,很好理解;效果图:

代码文件:

unitUnit1;

interface

uses

Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,

Dialogs,ExtCtrls,StdCtrls;

type

TForm1=class(TForm)

Button1:

TButton;

Button2:

TButton;

procedureButton1Click(Sender:

TObject);

procedureButton2Click(Sender:

TObject);

procedureFormDestroy(Sender:

TObject);

end;

var

Form1:

TForm1;

implementation

{$R*.dfm}

var

hTimer:

THandle;

{APC函数}

procedureTimerAPCProc(lpArgToCompletionRoutine:

Pointer;dwTimerLowValue:

DWORD;

dwTimerHighValue:

DWORD);stdcall;

begin

Form1.Text:

=IntToStr(StrToIntDef(Form1.Text,0)+1);

SleepEx(INFINITE,True);

end;

{线程入口函数}

functionMyThreadFun(p:

Pointer):

Integer;stdcall;

var

DueTime:

Int64;

begin

DueTime:

=0;

{SetWaitableTimer必须与SleepEx在同一线程}

ifSetWaitableTimer(hTimer,DueTime,1000,@TimerAPCProc,nil,False)then

begin

SleepEx(INFINITE,True);

end;

Result:

=0;

end;

procedureTForm1.Button1Click(Sender:

TObject);

var

ID:

DWORD;

begin

{建立WaitableTimer对象}

ifhTimer=0thenhTimer:

=CreateWaitableTimer(nil,True,nil);

CreateThread(nil,0,@MyThreadFun,nil,0,ID);{建立线程}

end;

procedureTForm1.Button2Click(Sender:

TObject);

begin

CancelWaitableTimer(hTimer);{取消定时器}

end;

procedureTForm1.FormDestroy(Sender:

TObject);

begin

CloseHandle(hTimer);

end;

end.

窗体文件:

objectForm1:

TForm1

Left=0

Top=0

Caption='Form1'

ClientHeight=113

ClientWidth=203

Color=clBtnFace

Font.Charset=DEFAULT_CHARSET

Font.Color=clWindowText

Font.Height=-11

Font.Name='Tahoma'

Font.Style=[]

OldCreateOrder=False

PixelsPerInch=96

TextHeight=13

objectButton1:

TButton

Left=55

Top=32

Width=97

Height=25

Caption=#21551#21160#23450#26102#22120

TabOrder=0

OnClick=Button1Click

end

objectButton2:

TButton

Left=55

Top=63

Width=97

Height=25

Caption=#21462#28040#23450#26102#22120

TabOrder=1

OnClick=Button2Click

end

end

使用APC回调函数才是WaitableTimer的正途,下次该是如何给这个函数传递参数了.

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 法律文书 > 调解书

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1