function CreateWaitableTimer(lpTimerAttributes: PSecurityAttributes; {安全}bManualReset: BOOL;    {True: 可调度多个线程; False: 只调度一个线程}lpTimerName: PWideChar {名称}
): THandle; stdcall;     {返回句柄}function SetWaitableTimer(hTimer: THandle;                         {句柄}var lpDueTime: TLargeInteger;            {起始时间}lPeriod: Longint;                        {间隔时间}pfnCompletionRoutine: TFNTimerAPCRoutine;{回调函数的指针}lpArgToCompletionRoutine: Pointer;       {给回调函数的参数}fResume: BOOL                            {是否唤醒系统}
): BOOL; stdcall;                          {}

WaitableTimer 对象较复杂, 其基本的理念是让等候的线程在指定的时间运行.

像其他同类对象一样, 先要建立(CreateWaitableTimer), 建立函数的第二个参数决定是调度一个线程还是所有等候的线程; 这一点和信号对象(Semaphore) 有些类似, 不过 Semaphore 可以指定可驱动线程的具体数目.

和其他同类对象不同的是: 在 CreateWaitableTimer 以后, WaitableTimer 对象并没有马上开始工作;
再调用 SetWaitableTimer 函数后才能让它发挥作用. 这又有点像 Event 对象.

SetWaitableTimer 函数比较麻烦, 得慢慢来, 譬如这样使用:


varhWaitableTimer: THandle; {WaitableTimer 对象的句柄变量应该是全局的}procedure TForm1.Button1Click(Sender: TObject);
varDueTime: Int64;
begin{建立 WaitableTimer 对象并返回句柄}hWaitableTimer := CreateWaitableTimer(nil, True, nil); {中间的 True 表示可驱动多个线程}DueTime := 0; {这将是 SetWaitableTimer 的第二个参数; 因为是 var 参数, 不能直接给常量}SetWaitableTimer(hWaitableTimer, {WaitableTimer 对象的句柄}DueTime,        {起始时间, 这里给的是 0}0,              {间隔时间, 这里给的也是 0}nil,            {暂不用回调函数}nil,            {当然也不需要给回调函数参数了}False {此值若是 True, 即使系统在屏保或待机状态, 时间一到线程和系统将都被唤醒!});
end;{再说明:
起始时间(第二个参数)有三种赋值方法:
1、> 0 时是绝对时间, 是一个 TFileTime 格式的时间(具体赋值方法后面详解);
2、< 0 时是相对时间, 相对是相对于当前, 譬如 -50000000 表示 5 秒钟后执行(单位是0.1毫秒, 后面详述);
3、= 0 时, 立即执行, 不再等待; 上面的举例和下面第一个例子我们先用 0.间隔时间(第三个参数)有两种情况:
1、譬如 5000 表示每隔 5 秒钟执行一次, 其单位是毫秒; 本页第二个例子使用了 500(半秒);
2、如果赋值为 0, 表示根据起始时间只执行一次, 不再重复执行.回调函数及其参数(第四、五个参数), 这会牵扯出一个更复杂的话题(APC), 暂时不用它, 后面再说.最后一个参数上面已经说清楚了, 我也测试了一下(分别在屏保和待机状态下), 很有效!
}

第一个例子我们将尽量简单的使用它(但这样体现不出它的优势):
CreateWaitableTimer 时我们就决定让它可控制多个线程;
SetWaitableTimer 时先让它立即参与控制, 只执行一次, 也不使用回调函数.



本例效果图:



代码文件:


unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls;typeTForm1 = class(TForm)Button1: TButton;procedure Button1Click(Sender: TObject);procedure FormDestroy(Sender: TObject);end;varForm1: TForm1;implementation{$R *.dfm}varf: Integer;hWaitableTimer: THandle; {等待定时器对象的句柄}function MyThreadFun(p: Pointer): DWORD; stdcall;
vari,y: Integer;
beginInc(f);y := 20 * f;if WaitForSingleObject(hWaitableTimer, INFINITE) = WAIT_OBJECT_0 thenbeginfor i := 0 to 1000 dobeginForm1.Canvas.Lock;Form1.Canvas.TextOut(20, y, IntToStr(i));Form1.Canvas.Unlock;Sleep(1);end;end;Result := 0;
end;procedure TForm1.Button1Click(Sender: TObject);
varThreadID: DWORD;DueTime: Int64;
beginhWaitableTimer := CreateWaitableTimer(nil, True, nil);DueTime := 0;SetWaitableTimer(hWaitableTimer, DueTime, 0, nil, nil, False);Repaint; f := 0;CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
end;procedure TForm1.FormDestroy(Sender: TObject);
beginCloseHandle(hWaitableTimer);
end;end.

窗体文件:


object Form1: TForm1Left = 0Top = 0Caption = 'Form1'ClientHeight = 116ClientWidth = 179Color = clBtnFaceFont.Charset = DEFAULT_CHARSETFont.Color = clWindowTextFont.Height = -11Font.Name = 'Tahoma'Font.Style = []OldCreateOrder = FalseOnDestroy = FormDestroyPixelsPerInch = 96TextHeight = 13object Button1: TButtonLeft = 96Top = 83Width = 75Height = 25Caption = 'Button1'TabOrder = 0OnClick = Button1Clickend
end

下面是一个每隔半秒钟(500ms)执行一次的例子(窗体文件同上):



本例效果图:



代码文件:


unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls;typeTForm1 = class(TForm)Button1: TButton;procedure Button1Click(Sender: TObject);procedure FormDestroy(Sender: TObject);end;varForm1: TForm1;implementation{$R *.dfm}varf: Integer;hWaitableTimer: THandle;function MyThreadFun(p: Pointer): DWORD; stdcall;
vari,y: Integer;
beginInc(f);y := 20 * f;{这里和上面不同, 把等待弄到循环里面了}for i := 0 to 1000 dobeginif WaitForSingleObject(hWaitableTimer, INFINITE) = WAIT_OBJECT_0 thenbeginForm1.Canvas.Lock;Form1.Canvas.TextOut(20, y, IntToStr(i));Form1.Canvas.Unlock;
//      Sleep(1);end;end;Result := 0;
end;procedure TForm1.Button1Click(Sender: TObject);
varThreadID: DWORD;DueTime: Int64;
beginhWaitableTimer := CreateWaitableTimer(nil, False, nil); {这里的参数也和上面不一样}DueTime := 0;SetWaitableTimer(hWaitableTimer, DueTime, 500, nil, nil, False); {500 ms}Repaint; f := 0;CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
end;procedure TForm1.FormDestroy(Sender: TObject);
beginCloseHandle(hWaitableTimer);
end;end.

转载于:https://www.cnblogs.com/del/archive/2009/02/16/1392049.html

多线程编程(14) - 多线程同步之 WaitableTimer (等待定时器对象)相关推荐

  1. 多线程编程(15) - 多线程同步之 WaitableTimer (等待定时器对象)[续]

    本次专门研究下 SetWaitableTimer 的第二个参数(起始时间). 它有正值.负值.0值三种情况, 前面已用过 0值. 先学习负值(相对时间), 也就是从当前算起隔多长时间开始执行. 这个相 ...

  2. 多线程同步之 WaitableTimer (等待定时器对象)[续三]

    根据 WaitableTimer 的主要功用, 现在再把它放在 "线程同步" 的话题中讨论有点不合适了, 就要结束它. TimerAPCProc(lpArgToCompletion ...

  3. Linux多线程编程---线程间同步(互斥锁、条件变量、信号量和读写锁)

    本篇博文转自http://zhangxiaoya.github.io/2015/05/15/multi-thread-of-c-program-language-on-linux/ Linux下提供了 ...

  4. Win32多线程编程(3) — 线程同步与通信

    一.线程间数据通信 系统从进程的地址空间中分配内存给线程栈使用.新线程与创建它的线程在相同的进程上下文中运行.因此,新线程可以访问进程内核对象的所有句柄.进程中的所有内存以及同一个进程中其他所有线程的 ...

  5. 多线程编程、线程同步|安全和线程通信

    多线程编程 多线程的优势 线程在程序中是独立的.并发的执行流,与分隔的进程相比,进程中的线程之间的隔离程度要小.他们共享内存.文件句柄和其他每个进程应有的状态. 因为线程的划分尺度小于进程,使得多线程 ...

  6. java多线程同步与死锁,廖雪峰Java11多线程编程-2线程同步-3死锁

    在多线程编程中,要执行synchronized块,必须首先获得指定对象的锁. 1.Java的线程锁是可重入的锁 public void add(int m){ synchronized (lock){ ...

  7. 多线程编程java_Java多线程编程

    Java给多线程编程提供了内置的支持.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销. ...

  8. python多线程编程_python多线程编程(1): python对多线程的支持

    前面介绍过多线程的基本概念,理解了这些基本概念,掌握python多线程编程就比较容易了. 在开始之前,首先要了解一下python对多线程的支持. 虚拟机层面 Python虚拟机使用GIL(Global ...

  9. 多线程编程 java_java多线程编程

    一.多线程的优缺点 多线程的优点: 1)资源利用率更好 2)程序设计在某些情况下更简单 3)程序响应更快 多线程的代价: 1)设计更复杂 虽然有一些多线程应用程序比单线程的应用程序要简单,但其他的一般 ...

最新文章

  1. LESS 的 operation 是 特性
  2. php中函数的定义格式,在php中函数定义的格式
  3. GDCM:DICOM文件转储图像标题信息的测试程序
  4. 指数分布的期望推导过程
  5. 逻辑回归能摆平二分类因变量,那……不止二分类呢?
  6. 【iOS】Illegal Configuration: The Label outlet from the ViewController to the UILabel is invalid. Outl
  7. HDU 3037 Saving Beans [Lucas定理]
  8. 因子分析 factor analysis (二 ) : 因子分析模型
  9. 基于微信小程序的校园论坛系统开发过程
  10. 二元最佳前缀码_贪心-最优前缀码
  11. 回溯法解决部落冲突问题
  12. 互联网快讯:极米Z6X Pro、极米H3S音画表现出众;快狗打车赴港IPO;vivo回应造车传闻
  13. Android通过Canvas手绘一个折线图
  14. 【MyBatis笔记12】MyBatis中二级缓存相关配置内容
  15. vue的两个核心是什么
  16. 软件研发的项目经理都在用哪些好的设计和管理的软件工具?
  17. 计算机联锁的英语文献,计算机联锁系统毕业论文中英文资料外文翻译文献
  18. ensp-网络地址转换
  19. iOS JS与OC交互
  20. python 新式类 旧式类_Python新式类与经典类(旧式类)的区别

热门文章

  1. java lambda表达式_「JAVA8」- Lambda 表达式
  2. oracle不弹出另存为,Oracle另存为~
  3. mysql有符号数_mysql里面有符号整数类型有关问题,请指点,多谢
  4. mysql workbench 存储过程_MySQL Workbench创建存储过程教程示例
  5. 动态添加Table tbody 给option 下拉框动态赋值 逻辑删除
  6. docker+mysql+授权_docker安装mysql, 授权远程连接
  7. java中一级缓存二级缓存_[Java] hibernate 一级缓存和二级缓存
  8. # 字节数组转uint32_字节跳动客户端校招面经(21届秋招内推)
  9. ppt课堂流程图_4个超实用的PPT制作技巧:开学提升备课质量,资深老师都在用
  10. java设置类的字符格式_java类---与格式化相关的类