睡眠在线程中的替代方案

Alternative to sleep inside a thread

本文关键字:方案 线程      更新时间:2023-10-16

各种答案表明,睡在线程内是个坏主意,例如:避免睡眠。为什么?通常给出的一个原因是,如果线程正在休眠,则很难优雅地退出线程(通过发出终止信号)。

比方说,我想定期检查网络文件夹中的新文件,可能每10秒检查一次。这似乎非常适合优先级设置为低(或最低)的线程,因为我不希望潜在的耗时文件I/O影响我的主线程。

有哪些替代方案?代码在Delphi中给出,但同样适用于任何多线程应用程序:

procedure TNetFilesThrd.Execute();
begin
    try
        while (not Terminated) do
            begin
            // Check for new files
            // ...
            // Rest a little before spinning around again
            if (not Terminated) then
                Sleep(TenSeconds);
            end;
    finally
        // Terminated (or exception) so free all resources...
    end;
end;

一个小的修改可能是:

// Rest a little before spinning around again
nSleepCounter := 0;
while (not Terminated) and (nSleepCounter < 500) do
    begin
    Sleep(TwentyMilliseconds);
    Inc(nSleepCounter);
    end;

但这仍然涉及睡眠。。。

执行此操作的标准方法是等待取消事件。在看起来像这样的伪代码中:
while not Terminated do
begin
  // Check for new files
  // ...
  // Rest a little before spinning around again
  FTerminationEvent.WaitFor(TenSeconds);
end;

为了终止,您需要覆盖TerminatedSet:

procedure TMyThread.TerminatedSet;
begin
  inherited;
  FTerminationEvent.SetEvent; // abandon the wait in the thread method
end;

对该事件的等待要么超时,要么由于该事件已发出信号而终止。这允许您的线程暂停一段时间,而不会给CPU带来负担,而且还可以对终止请求保持响应。

如果这是我的工作,我想我会用一个包含TTimer的包装类来解决它,每10秒生成一个新线程。

生成一个新线程的成本有些高,但如果是每10秒才执行一次的操作,我认为对主线程的性能影响可以忽略不计。

步骤:

  1. 创建一个包装类TMyFileSearcher
  2. 让它包含一个TTimer
  3. 每次定时器命中时,生成一个新线程并搜索文件
  4. 向TMyFileSearcher添加一个OnTerminate处理程序,以处理返回的文件

还有一些其他的考虑因素,比如跟踪线程是否已经派生,这样就不会在旧线程运行时创建新线程。

但是,除此之外,我认为它应该非常直接地实施。