【问题标题】:Timing and VCL synchronize (in/from thread)时序和 VCL 同步(在/从线程)
【发布时间】:2014-02-14 14:26:57
【问题描述】:

我想刷新 Treenode.text(带有经过的时间)并使用来自同一线程的计时器。正如我所读到的,它不建议在线程中使用 TTimer*,但是,用什么来代替呢?谢谢。

*我想使用一些时间而不是 sleep()。不仅因为那很俗气(?),而且我必须这样做,否则我只能在每一秒内刷新 treenodetext。)>>

unit master_slave

...

Tsrch_slave_thread = class(TThread)   
protected
  procedure Execute; override;
public
  master: TMaster;         
end;

TMaster = class(TObject)
private
  ...
  FMasterNode: TTreeview; 
  Fsw: TStopWatch;
  Fslave_search_thread : Tsrch_slave_thread;
  ...
end;

...

implementation

...

procedure Tsrch_slave_thread.Execute;
var
  searchactive: integer;
begin
  while not terminated do begin
    searchactive := master.CMD_LISTCNT 
    if searchactive = 1 then //(master.CMD_LISTCNT's return value = 1, if master finished search on the bus)
      exit;
    sleep(1000); //dont want to flood the master with UDP packets... (master.CMD_LISTCNT sends UDP packets)
    synchronize(procedure begin
      with FmasterNode do  
        text := text + floattostr(Fsw.ElapsedMilliseconds / 1000);
    end);
  end;
end;

【问题讨论】:

    标签: multithreading delphi timing synchronize


    【解决方案1】:

    使用可等待事件代替Sleep(1000)

    例如TSimpleEvent

    FMySimpleEvent.WaitFor(1000);
    

    如果你想提前退出线程,重写TThread.DoTerminate方法并调用:

    FMySimpleEvent.SetEvent;
    

    类似这样的:

    procedure Tsrch_slave_thread.Execute;
    var
      searchactive: integer;
    begin
      while not terminated do begin
        searchactive := master.CMD_LISTCNT 
        if searchactive = 1 then (master.CMD_LISTCNT's return value = 1, if search finished)
          exit;
        if (FMySimpleEvent.WaitFor(1000) = wrTimeOut) then
          synchronize(procedure begin
            with FmasterNode do  
              text := text + floattostr(Fsw.ElapsedMilliseconds / 1000);
          end);
      end;
    end;
    
    procedure Tsrch_slave_thread.DoTerminate;
    begin
      Inherited;
      FMySimpleEvent.SetEvent;
    end;
    

    【讨论】:

    • +1。这是处理等待特定操作完成的正确方法。 Sleep 或计时器只能用于处理基于特定时间长度的事情;在等待离散事件时,请使用可等待信号。
    • @Mason 此代码正在等待特定的时间长度
    • @LU RD,谢谢。 (为什么我不能在 TStopWatch 上免费通话?)
    • TStopWatch 是带有方法的记录,也就是高级记录。它不在堆上分配,也不需要释放。
    • 呃,因为我看到你的一个例子释放了一个 TStopWatch 实例,但现在我看到这是一个基于 delphi.about 文章的类。
    【解决方案2】:

    您可以在线程中使用计时器,但不能使用TTimer。您必须根据SetTimer 自己制作。而且您还需要创建自己的窗口来处理消息,因为您不能在线程中使用AllocateHWnd。现在,如果您知道不会显示任何模态对话框或运行任何模态大小循环或模态菜单循环,那么您可以使用无窗口计时器。

    但这一切都迫使您在线程中实现消息循环。这增加了另一层复杂性。在后台线程中实现计时器是阻塞方法合理的少数场景之一。我建议你采用这种方法。

    如果您的时间间隔足够短,那么您可以使用Sleep。缺点是您需要等待对Sleep 的调用返回,然后才能终止线程。因此,对于较长的时间间隔,这可能是一个问题。

    如果您希望能够立即终止,您可以使用WaitForSingleObjectSyncObjs 单元中定义的事件类之一来等待超时事件,而不是使用Sleep。如果超时时间过去,则您的计时器已经过去。如果事件发出信号,那么您的线程应该会终止。

    【讨论】:

    • 想要使用计时器,因为这样我可以在不到一秒的时间内刷新树节点,但这真的毫无价值。将继续使用 FMySimpleEvent.WaitFor 或 sleep()。谢谢。
    • 睡眠、定时器和事件具有相同的分辨率。所有频率都可以远大于 1Hz。
    • 是的,但我必须将其保留在 1 秒,因为我不想更频繁地发送 udp 数据包。最初的想法是:仅每 1 秒发送一次 udp 数据包,但每隔 10 毫秒刷新一次 treenode.text。
    猜你喜欢
    • 1970-01-01
    • 2013-04-07
    • 1970-01-01
    • 2015-05-22
    • 2010-10-03
    • 1970-01-01
    • 2010-10-14
    相关资源
    最近更新 更多