【问题标题】:How to implement thread which periodically checks something using minimal resources?如何实现使用最少资源定期检查某些内容的线程?
【发布时间】:2011-12-07 08:22:03
【问题描述】:

我想在后台运行一个线程,它会检查与给定时间间隔的某个服务器的连接。例如每 5 秒一次。

我不知道这是否有一个好的“设计模式”?如果我没记错的话,我在某个地方读到过它的执行方法中的休眠线程并不好。但我可能错了。

另外,我可以使用普通的 TThread 类或 OTL 线程库。

有什么想法吗?

谢谢。

【问题讨论】:

    标签: multithreading delphi delphi-2009 tthread omnithreadlibrary


    【解决方案1】:

    在OmniThreadLibrary,你会这样做:

    uses
      OtlTask,
      OtlTaskControl;
    
    type
      TTimedTask = class(TOmniWorker)
      public
        procedure Timer1;
      end;
    
    var
      FTask: IOmniTaskControl;
    
    procedure StartTaskClick;
    begin
      FTask := CreateTask(TTimedTask.Create())
        .SetTimer(1, 5*1000, @TTimedTask.Timer1)
        .Run;
    end;
    
    procedure StopTaskClick;
    begin
      FTask.Terminate;
      FTask := nil;
    end;
    
    procedure TTimedTask.Timer1;
    begin
      // this is triggered every 5 seconds
    end;
    

    至于在 Execute 中休眠 - 这取决于您的操作方式。如果您使用睡眠,那么这可能不是很明智(例如,因为它会阻止线程在睡眠期间停止)。用 WaitForSingleObject 睡觉很好。

    TThread 和 WaitForSingleObject 的一个例子:

    type
      TTimedThread = class(TThread)
      public
        procedure Execute; override;
      end;
    
    var
      FStopThread: THandle;
      FThread: TTimedThread;
    
    procedure StartTaskClick(Sender: TObject);
    begin
      FStopThread := CreateEvent(nil, false, false, nil);
      FThread := TTimedThread.Create;
    end;
    
    procedure StopTaskClick(Sender: TObject);
    begin
      SetEvent(FStopThread);
      FThread.Terminate;
      FThread.Free;
      CloseHandle(FStopThread);
    end;
    
    { TTimedThread }
    
    procedure TTimedThread.Execute;
    begin
      while WaitForSingleObject(Form71.FStopThread, 5*1000) = WAIT_TIMEOUT do begin
        // this is triggered every 5 seconds
      end;
    end;
    

    OTL 定时器的实现类似于上面的 TThread 代码。 OTL 计时器保存在优先级列表中(基本上计时器按“下一次发生”时间排序),TOmniWorker 中的内部 MsgWaitForMultipleObjects 调度程序为最高优先级计时器指定适当的超时值。

    【讨论】:

    • 谢谢 gabr,我想在你的论坛上问你这个问题,但它不起作用。 +1
    • 是的,域服务器有问题;我正在努力。
    • 您能告诉我们更多您是如何实施您的计时解决方案的吗?也许写一篇关于它的博客文章?:)
    • 谢谢。当它运行时,我会在你的论坛中深入了解更多细节。
    • 发生了什么事,大卫?窗口事件?如果你编写自己的线程循环,那么你可以使用任何你想要的,但你也可以选择退出它,让 OTL 自己处理线程循环。
    【解决方案2】:

    您可以使用事件并通过循环实现TThread 后代的Execute 方法,其中WaitForSingleObject 等待事件,指定超时。这样您就可以在需要时立即唤醒线程,例如终止时。

    【讨论】:

      【解决方案3】:

      如果线程在应用程序的生命周期内运行,可以在应用程序关闭时由操作系统简单地终止并且不需要准确的计时,为什么还要使用需要比 sleep(5000) 更多输入的解决方案?

      【讨论】:

      • 因为您可以等待长达 5 秒的时间让线程(以及程序)终止。
      • 我,我只是让线程休眠 1000 毫秒,然后它会醒来,检查是否已终止,然后检查是否有工作要做。线程在系统上几乎是空闲的,它运行良好且高效。当然,关闭时有 1 秒延迟,但我首先在所有线程上调用 Terminate,然后执行 WaitFors,因此所有线程的总延迟为 1 秒,而不是 1 秒乘以线程数。由于某些线程的工作时间更长,因此成本可以忽略不计。
      • @Torbins 等 - 如果你不销毁线程,dtor 将不会被调用,也不会等待!
      • @gabr 你可以等,当然,但你为什么要等呢?您不希望您的应用立即关闭吗?
      • TThread.Terminate 只是设置了一个标志,AFAIK,所以不会造成任何延迟。导致延迟的是 TThread.WaitFor,无论是显式的还是从 TThread.Destroy 调用的。如果你不调用 TThread.WaitFor,你的应用不会被阻塞。
      【解决方案4】:

      要添加另一种实现 5 秒事件的方法,可以使用类似于 TTimer 但不依赖于您的应用程序的多媒体定时器。配置后(您可以设置一次性或重复),它会在另一个线程中调用您。就其性质而言,它非常准确(在 1ms 以内)。见一些sample Delphi code here。

      调用定时器的代码很简单,所有Windows平台都支持。

      【讨论】:

        【解决方案5】:

        【讨论】:

        • 为什么这比这里讨论的其他解决方案更好/更差? (IOW,你应该改进你的答案)。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-05
        • 2020-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多