zoukankan      html  css  js  c++  java
  • Delphi

    明天去坐火车,回家,今天就没有事做,本来在弄一个跨进程获取其他程序里面组件,如ListView,ListBox,Button等的信息,突然有个想法自己写个Timer,不用SetTimer函数,我们自己用个多线程也正好实现这个.反正前段时间多线程也弄得比较多,本来想单独讲讲的,现在就用个例子来说明吧.
    写成一个控件:utTimer.pas

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    unit utTimer;
     
    interface
    uses
      Windows,SysUtils,Classes;
     
    type
      THuangJackyTimerThread = class;
      THuangJackyTimer = class(TComponent)
      private
        FTimeInterval:Integer;
        FOnTimerDo:TNotifyEvent;
        FTimerThread:THuangJackyTimerThread;
        FEnable:Boolean;
        procedure SetEnable(bBool:Boolean);
        procedure SetTimeInterval(aValue:Integer);
     
        procedure StopThread;
        procedure StartThread;
      public
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;
      published
        property TimeInterval:Integer  read FTimeInterval write SetTimeInterval;
        property OnTimerDo:TNotifyEvent  read FOnTimerDo write FOnTimerDo;
        property Enable:Boolean  read FEnable write SetEnable;
      end;
     
      THuangJackyTimerThread = class(TThread)
      private
        FTimer:THuangJackyTimer;
        FTerminateHandle,FExitHandle,FStartHandle,FStopHandle:Cardinal;
     
        procedure DoTimerEvent;
      protected
        procedure Execute;override;
      public
        constructor Create(AOwner: THuangJackyTimer);
        destructor Destroy; override;
      end;
     
    procedure Register;
     
     
    implementation
     
    procedure Register;
    begin
      RegisterComponents('HuangJacky',[THuangJackyTimer]);
    end;
     
    { THuangJackyTimer }
     
    constructor THuangJackyTimer.Create(AOwner: TComponent);
    begin
      inherited;
      FTimeInterval:=1000;
      FTimerThread:=THuangJackyTimerThread.Create(Self);
      FTimerThread.Resume;
    end;
     
    destructor THuangJackyTimer.Destroy;
    begin
      SetEvent(FTimerThread.FTerminateHandle);
      WaitForSingleObject(FTimerThread.FExitHandle,5000);
      FTimerThread.Free;
      inherited;
    end;
     
    procedure THuangJackyTimer.SetEnable(bBool: Boolean);
    begin
      if Enable = bBool then
        Exit;
      if csDesigning in ComponentState then
        Exit;
      if Enable then
      begin
        StopThread;
        FEnable:=False;
      end
      else
      begin
        StartThread;
        FEnable:=True;
      end;
    end;
     
    procedure THuangJackyTimer.SetTimeInterval(aValue: Integer);
    begin
      if FTimeInterval = aValue then
        Exit;
      InterlockedExchange(FTimeInterval,aValue);
    end;
     
    procedure THuangJackyTimer.StartThread;
    begin
      SetEvent(FTimerThread.FStartHandle);
    end;
     
    procedure THuangJackyTimer.StopThread;
    begin
      SetEvent(FTimerThread.FStopHandle)
    end;
     
    { THuangJackyTimerThread }
     
    constructor THuangJackyTimerThread.Create(AOwner: THuangJackyTimer);
    var
      sTmp,sTmp1:string;
    begin
      inherited Create(True);
      Assert(Assigned(AOwner));
      //自己创建,自己释放,这样能保证100%不内存泄露,个人习惯
      FreeOnTerminate:=False;
      FTimer:=AOwner;
      sTmp:=FTimer.Name;
      sTmp1:=DateTimeToStr(Now());
      FTerminateHandle:=CreateEvent(nil,True,False,PChar(sTmp + sTmp1 + 'T'));
      Assert(FTerminateHandle<>0);
      //用这个Event来通知主线程:Timer线程已经执行完了
      FExitHandle:=CreateEvent(nil,True,False,PChar(sTmp + sTmp1 + 'E'));
      Assert(FExitHandle<>0);
      FStartHandle:=CreateEvent(nil,True,False,PChar(sTmp + sTmp1 +'Sa'));
      Assert(FStartHandle<>0);
      FStopHandle:=CreateEvent(nil,True,False,PChar(sTmp + sTmp1 + 'So'));
      Assert(FStopHandle<>0);
    end;
     
    destructor THuangJackyTimerThread.Destroy;
    begin
       CloseHandle(FStopHandle);
       CloseHandle(FStartHandle);
       CloseHandle(FExitHandle);
       CloseHandle(FTerminateHandle);
      inherited;
    end;
     
    procedure THuangJackyTimerThread.DoTimerEvent;
    begin
      if Assigned(FTimer.OnTimerDo) then
        FTimer.OnTimerDo(FTimer);
    end;
     
    procedure THuangJackyTimerThread.Execute;
    var
      Waits1:array[0..2] of Cardinal;
      Waits2:array[0..1] of Cardinal;
     
      procedure DoTerminate;
      begin
        ResetEvent(FTerminateHandle);
        Terminate;
      end;
     
    begin
      Waits1[0]:=FStartHandle;
      Waits1[1]:=FTerminateHandle;
      Waits1[2]:=FStopHandle;
      Waits2[0]:=FStopHandle;
      Waits2[1]:=FTerminateHandle;
      //循环等待.
      while not Terminated do
        //每一次Wait后我们都需要判断下Terminate,不然在你等待的时候,线程就被Terminate了.
        //不过不判断也不要紧
        //因为Terminate只是将Terminated设置成True.
        //也就是如果不判断,就多运行一次.
        //但是这个例子里面因为内层也有一个While循环,所以必须判断
        case WaitForMultipleObjects(3,@Waits1,False,INFINITE) of
          WAIT_OBJECT_0 + 0:
            begin
              ResetEvent(FStartHandle);
              if Terminated then
                Break;
              while True do
              begin
                case WaitForMultipleObjects(2,@Waits2,False,FTimer.TimeInterval) of
                  WAIT_OBJECT_0 + 0:
                    begin
                      ResetEvent(FStopHandle);
                      Break
                    end;
                  WAIT_OBJECT_0 + 1:
                    begin
                      DoTerminate;
                      Break;
                    end;
                end;
                if Terminated then
                  Break;
                //执行Timer事件.
                Synchronize(DoTimerEvent);
              end;
            end;
          WAIT_OBJECT_0 + 1:
            DoTerminate;
          WAIT_OBJECT_0 + 2:
            ResetEvent(FStopHandle);
        end;
      SetEvent(FExitHandle);
    end;
     
    end.

    两百行的代码,比较简单,就是一个线程在循环等待事件,然后相应的事件做相应的事.
    其实主要是想说如何使用线程,我不喜欢将线程的FreeOnTerminate设置为True,因为感觉不安全,心里不踏实呀.
    测试例子:Unit1.pas

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    unit Unit1;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs,utTimer;
     
    type
      TForm1 = class(TForm)
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
        Timer:THuangJackyTimer;
        III:Integer;
        procedure DoTimer(S:TObject);
      public
        { Public declarations }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    procedure TForm1.DoTimer(S: TObject);
    begin
    //这个Timer不存在重入的情况,所以不需要先设置Enable为True
      Caption:=IntToStr(III);
      Inc(III);
    end;
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      Timer:=THuangJackyTimer.Create(Self);
      Timer.TimeInterval:=2000;
      Timer.OnTimerDo:=DoTimer;
      Timer.Enable:=True;
    end;
     
    end.

    D7和D2010上面都测试了一下,米有发现问题.
    如果有什么问题欢迎拍砖.哈哈

    http://www.cnblogs.com/huangjacky/archive/2010/02/10/1667217.html

  • 相关阅读:
    cgo中调用有函数指针参数的C函数
    为什么要微服务架构服务化?
    学习刘杨人像后期笔记纪要
    错误日志表设计
    通过jstack日志分析和问题排查
    【JVM】jmap命令详解----查看JVM内存使用详情
    【JVM】jstat命令详解---JVM的统计监测工具
    介绍几种常用的监控工具
    【转】Pinpoint分布式系统性能监控工具
    【转】Skywalking概述
  • 原文地址:https://www.cnblogs.com/findumars/p/5185232.html
Copyright © 2011-2022 走看看