文档章节

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

涂孟超
 涂孟超
发布于 2014/09/26 15:37
字数 1193
阅读 12
收藏 0
点赞 0
评论 0
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 函数比较麻烦, 得慢慢来, 譬如这样使用:
var
  hWaitableTimer: THandle; {WaitableTimer 对象的句柄变量应该是全局的}

procedure TForm1.Button1Click(Sender: TObject);
var
  DueTime: 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;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  f: Integer;
  hWaitableTimer: THandle; {等待定时器对象的句柄}

function MyThreadFun(p: Pointer): DWORD; stdcall;
var
  i,y: Integer;
begin
  Inc(f);
  y := 20 * f;
  if WaitForSingleObject(hWaitableTimer, INFINITE) = WAIT_OBJECT_0 then
  begin
    for i := 0 to 1000 do
    begin
      Form1.Canvas.Lock;
      Form1.Canvas.TextOut(20, y, IntToStr(i));
      Form1.Canvas.Unlock;
      Sleep(1);
    end;
  end;
  Result := 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ThreadID: DWORD;
  DueTime: Int64;
begin
  hWaitableTimer := 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);
begin
  CloseHandle(hWaitableTimer);
end;

end.

 
 
 
 
 

 

 

  

窗体文件:
object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 116
  ClientWidth = 179
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 96
    Top = 83
    Width = 75
    Height = 25
    Caption = 'Button1'
    TabOrder = 0
    OnClick = Button1Click
  end
end

 
 
 
 
 

 

 

  

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

本例效果图:



代码文件:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  f: Integer;
  hWaitableTimer: THandle;

function MyThreadFun(p: Pointer): DWORD; stdcall;
var
  i,y: Integer;
begin
  Inc(f);
  y := 20 * f;

  {这里和上面不同, 把等待弄到循环里面了}
  for i := 0 to 1000 do
  begin
    if WaitForSingleObject(hWaitableTimer, INFINITE) = WAIT_OBJECT_0 then
    begin
      Form1.Canvas.Lock;
      Form1.Canvas.TextOut(20, y, IntToStr(i));
      Form1.Canvas.Unlock;
//      Sleep(1);
    end;
  end;
  Result := 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ThreadID: DWORD;
  DueTime: Int64;
begin
  hWaitableTimer := 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);
begin
  CloseHandle(hWaitableTimer);
end;

end.

 
 
 
 
 

 

 

  

本文转载自:http://www.cnblogs.com/del/archive/2009/02/16/1392049.html

共有 人打赏支持
涂孟超
粉丝 12
博文 2011
码字总数 14107
作品 0
深圳
程序员
《Java多线程编程核心技术》读书笔记

《Java多线程编程核心技术》读书笔记。 第一章 Java多线程技能 使用Java多线程两种方式。 继承Thread类与实现Runnable接口。 线程的开始、中止、暂停、恢复、停止。 、、、、 线程的、、优先...

刀狂剑痴
2016/05/02
390
0
boost------asio库的使用1(Boost程序库完全开发指南)读书笔记

asio库基于操作系统提供的异步机制,采用前摄器设计模式(Proactor)实现了可移植的异步(或者同步)IO操作,而且并不要求多线程和锁定,有效地避免了多线程编程带来的诸多有害副作用。 目前asi...

LUIS1983
2016/12/23
30
0
C#多线程学习(六) 互斥对象

本系列文章导航 C#多线程学习(一) 多线程的相关概念 C#多线程学习(二) 如何操纵一个线程 C#多线程学习(三) 生产者和消费者 C#多线程学习(四) 多线程的自动管理(线程池) C#多线程学习(五) 多线...

Yamazaki
2012/03/29
0
0
C#多线程学习(三) 生产者和消费者

[1] C#多线程学习(三) 生产者和消费者 [2]C#多线程学习(三) 生产者和消费者 本系列文章导航 C#多线程学习(一) 多线程的相关概念 C#多线程学习(二) 如何操纵一个线程 C#多线程学习(三) 生产者...

Yamazaki
2012/03/29
0
0
delphi之多线程编程(一)

delphi之多线程编程(一) 本文的内容取自网络,并重新加以整理,在此留存仅仅是方便自己学习和查阅。所有代码均亲自测试 delphi7下测试有效。图片均为自己制作。 多线程应该是编程工作者的基础...

KavenSu
2014/01/22
0
0
【IT基础】windows核心编程整理(上)

小续 这是我11年看《windows核心编程》时所作的一些笔记,现整理出来共享给大家 windows核心编程整理(上) windows核心编程整理(下) 线程的基础知识 进程是不活泼的,进程从来不执行任何东...

wbf961127
2017/11/07
0
0
多线程的实现及其安全问题

一、进程和线程概述 1、进程:进程是一个具有独立功能的程序关于某个数据集合的一次运行活动,简单来说开启一个程序就开启了一个进程; 如果开启多个进程,它们之间是由于CPU的时间片在相互的...

走了丶
2017/08/23
0
0
Python标准库08 多线程与同步 (threading包)

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢! Python主要通过标准库中的threading包来实现多线程。在当今网络时代,每个服务器都会接收到大量的请求...

osDaniel
2014/09/21
0
0
delphi 中几种多线程操作方式

在了解多线程之前我们先了解一下进程和线程的关系 一个程序至少有一个主进程,一个进程至少有一个线程。 为了保证线程的安全性请大家看看下面介绍 Delphi多线程同步的一些处理方案大家可以参考...

moodlxs
2015/01/09
0
0
【PYTHON模块】threading模块

threading模块:利用CPU空闲时间执行多任务。Python的多线程实际是遇到IO操作就CPU切换到其它任务。 1、GIL (Global Interpreter Lock):全局解释器锁 作用就是保证同一时刻CPU只执行一个线程...

等你的破船
07/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Nginx配置error_page 404 500等自定义的错误页面

Nginx 做web server时, 开发中发现有时候的网站代码有错误,我们需要跳转到一个指定内容的错误页面: 1. 在nginx.conf配置文件上加上一句: fastcgi_intercept_errors on; 2. 服务中加上: er...

MichaelShu
9分钟前
0
0
社区系统:如何搭建旅游攻略社区

随着国内经济的快速发展,人民经济收入和生活水平的提高,越来越多的人们在节假日会选择旅行,旅游行业蓬勃发展,并呈逐年上升趋势,同时,大多数游客尤其是自由行游客会在旅行前访问旅行攻略...

ThinkSNS账号
10分钟前
0
0
微服务架构下的监控系统设计(一)——指标数据的采集展示

前言 微服务是一种架构风格,一个大型复杂软件应用通常由多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。...

UCloudTech
15分钟前
0
0
极客时间《趣谈网络协议》之开篇词学习笔记

出于个人兴趣,本人在极客时间购买了网易研究院云计算技术部的首席架构师刘超老师关于计算机网络的专栏之《趣谈网络协议》,由于知识版权原因,不能直接分享刘超老师的原文,所以,我会在每次...

aibinxiao
17分钟前
1
0
Activiti - 新一代的开源 BPM 引擎

Activiti 背景简介、服务和功能介绍 董 娜, 狄 浩, 和 张 晓篱 2012 年 7 月 23 日发布 背景介绍 Activiti 其核心是 BPMN 2.0 的流程引擎。BPMN 是目前被各 BPM 厂商广泛接受的 BPM 标准,全...

孟飞阳
23分钟前
0
0
最有效的方式来适配

最有效的方式来进行屏幕适配 在上代码之前先把屏幕相关的几个概念搞清楚:Density、DensityDpi、ScaleDensity。这里我们不过多讲解这些概念知识。 1.0 获取设计图的屏幕尺寸:这里我以360dp...

android-key
25分钟前
0
0
微信授权代码翻译样本

var a,b,c,d = ngx.call(1,2,3)var e = [];var f ;var g = function () {}var h = 1;var c = "abcdefg" + "222";var d = "asdasdasd" + a;var a = ngx >>> log();//......

钟元OSS
27分钟前
0
0
5、二维码生成工具类

一、maven引入依赖jar包 <dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.1.0</version></dependency><dependency><groupId>com.......

丑陋的皮囊
27分钟前
0
0
正则表达式

以前用正则表达式很少,大部分情况下matches一下就好了,这次遇到的情况比较特殊,因为对截取出来的数据比较敏感(日期),所以就重新熟悉了一下,感觉有必要记录一下: /** * 从字符串中...

lost_keke
29分钟前
2
0
Java语言学习(十一):枚举类型和泛型

Java中一个重要的类型:枚举,它可以用来表示一组取值范围固定的变量,使用 enum 关键字定义枚举类型,其中元素不能重复,通常大写表示。利用Java的反射机制,可以在运行时分析类,如查看枚举...

海岸线的曙光
32分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部