多线程编程(14) - 多线程同步之 WaitableTimer (等待定时器对象)
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 (等待定时器对象)相关推荐
- 多线程编程(15) - 多线程同步之 WaitableTimer (等待定时器对象)[续]
本次专门研究下 SetWaitableTimer 的第二个参数(起始时间). 它有正值.负值.0值三种情况, 前面已用过 0值. 先学习负值(相对时间), 也就是从当前算起隔多长时间开始执行. 这个相 ...
- 多线程同步之 WaitableTimer (等待定时器对象)[续三]
根据 WaitableTimer 的主要功用, 现在再把它放在 "线程同步" 的话题中讨论有点不合适了, 就要结束它. TimerAPCProc(lpArgToCompletion ...
- Linux多线程编程---线程间同步(互斥锁、条件变量、信号量和读写锁)
本篇博文转自http://zhangxiaoya.github.io/2015/05/15/multi-thread-of-c-program-language-on-linux/ Linux下提供了 ...
- Win32多线程编程(3) — 线程同步与通信
一.线程间数据通信 系统从进程的地址空间中分配内存给线程栈使用.新线程与创建它的线程在相同的进程上下文中运行.因此,新线程可以访问进程内核对象的所有句柄.进程中的所有内存以及同一个进程中其他所有线程的 ...
- 多线程编程、线程同步|安全和线程通信
多线程编程 多线程的优势 线程在程序中是独立的.并发的执行流,与分隔的进程相比,进程中的线程之间的隔离程度要小.他们共享内存.文件句柄和其他每个进程应有的状态. 因为线程的划分尺度小于进程,使得多线程 ...
- java多线程同步与死锁,廖雪峰Java11多线程编程-2线程同步-3死锁
在多线程编程中,要执行synchronized块,必须首先获得指定对象的锁. 1.Java的线程锁是可重入的锁 public void add(int m){ synchronized (lock){ ...
- 多线程编程java_Java多线程编程
Java给多线程编程提供了内置的支持.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销. ...
- python多线程编程_python多线程编程(1): python对多线程的支持
前面介绍过多线程的基本概念,理解了这些基本概念,掌握python多线程编程就比较容易了. 在开始之前,首先要了解一下python对多线程的支持. 虚拟机层面 Python虚拟机使用GIL(Global ...
- 多线程编程 java_java多线程编程
一.多线程的优缺点 多线程的优点: 1)资源利用率更好 2)程序设计在某些情况下更简单 3)程序响应更快 多线程的代价: 1)设计更复杂 虽然有一些多线程应用程序比单线程的应用程序要简单,但其他的一般 ...
最新文章
- LESS 的 operation 是 特性
- php中函数的定义格式,在php中函数定义的格式
- GDCM:DICOM文件转储图像标题信息的测试程序
- 指数分布的期望推导过程
- 逻辑回归能摆平二分类因变量,那……不止二分类呢?
- 【iOS】Illegal Configuration: The Label outlet from the ViewController to the UILabel is invalid. Outl
- HDU 3037 Saving Beans [Lucas定理]
- 因子分析 factor analysis (二 ) : 因子分析模型
- 基于微信小程序的校园论坛系统开发过程
- 二元最佳前缀码_贪心-最优前缀码
- 回溯法解决部落冲突问题
- 互联网快讯:极米Z6X Pro、极米H3S音画表现出众;快狗打车赴港IPO;vivo回应造车传闻
- Android通过Canvas手绘一个折线图
- 【MyBatis笔记12】MyBatis中二级缓存相关配置内容
- vue的两个核心是什么
- 软件研发的项目经理都在用哪些好的设计和管理的软件工具?
- 计算机联锁的英语文献,计算机联锁系统毕业论文中英文资料外文翻译文献
- ensp-网络地址转换
- iOS JS与OC交互
- python 新式类 旧式类_Python新式类与经典类(旧式类)的区别
热门文章
- java lambda表达式_「JAVA8」- Lambda 表达式
- oracle不弹出另存为,Oracle另存为~
- mysql有符号数_mysql里面有符号整数类型有关问题,请指点,多谢
- mysql workbench 存储过程_MySQL Workbench创建存储过程教程示例
- 动态添加Table tbody 给option 下拉框动态赋值 逻辑删除
- docker+mysql+授权_docker安装mysql, 授权远程连接
- java中一级缓存二级缓存_[Java] hibernate 一级缓存和二级缓存
- # 字节数组转uint32_字节跳动客户端校招面经(21届秋招内推)
- ppt课堂流程图_4个超实用的PPT制作技巧:开学提升备课质量,资深老师都在用
- java设置类的字符格式_java类---与格式化相关的类