带有超时的WaitForSingleObject会在超时后返回很长时间

这几乎是遗留代码,涉及一个简单的TThread,用作定时器,基于WaitForSingleObject()和事件句柄,就像这样

TTimerThread = class(TThread)
private
  FInterval: cardinal;
  FEvent: THandle;
  FSomeClass: TSomeClass;
protected
  procedure Execute; override;
end;

....

procedure TTimerThread.Execute;
var res: cardinal;
begin
  repeat
    log('Start WaitForSingleObject() with %d', [FInterval]);
    res := WaitForSIngleObject(FEvent, FInterval);
    log('End WaitForSingleObject() with result %d', [res]);
    if res = WAIT_TIMEOUT then
      if not Terminated then
        Synchronize(FSomeClass.SomeMethod);
  until Terminated;
end;

代码有点简单,就某些特定于应用程序的故障检查(何时不启动)和日志记录而言。

日志调用将显示在日志文件中,类似于:

2016/11/12 17:49:08:056 $1130 llDebug Start WaitForSingleObject() with 20
2016/11/12 17:49:09:015 $1130 llDebug End WaitForSingleObject() with result 258

日志功能以格式打印NOW的值,$ 1130是当前线程,llDebug是日志级别。 这两个调用之间没有记录(日志文件是“功能”/“模块”)

在这种情况下,等待时间高达959毫秒!

FEvent成员是在主线程中创建的(就像线程计时器本身一样):

FEvent := CreateEvent(nil, false, false, nil);

所以线程本身不会创建窗口,也不会使用COM或类似的东西。 如果SomeMethod会使用这种方法,它将在一个Synchronized调用中,以便在主线程中执行。 然而,对于这个特定的测试,SomeMethod只是在TImage上绘制。

该代码计算FInterval为20 ms。 该线程大约每30/31 ms触发一次,最有可能是由于Windows计时器分辨率。

我们有一个客户运行Windows 10,WaitForSingleObject()每隔几分钟(相隔好几分钟)就会在400+ ms以后才会返回。

SomeMethod在1 ms内执行,因为它没有做太多处理。

我们不需要高分辨率的计时器,因为当前的代码在其他地方都能正常工作,并且每30ms一次就足够了,即使是10-15毫秒的“错误”也是如此。

计时器控制一堆操作,这就是为什么它以大约20ms的间隔执行的原因,但是对于这个问题,我们已经消除了其他所有操作(显式地),只剩下1个操作正在运行,这就是我们如何调试它并查看WaitForSingleObject( )每隔几分钟400+毫秒后不会返回。

在WaitForSingleObject()之前有一个日志调用,并且之后有一个日志调用(也记录了间隔),所以即使间隔为20ms,WaitForSingleObject()也会在400 ms以上返回。 如预期的那样,日志记录显示WaitForSingleObject()的返回值为WAIT_TIMEOUT。

问题是:WaitForSingleObject()中可能导致这种行为的原因是什么? 我的意思是,由于CPU繁忙,线程太多(而不是此应用中的情况),但由于峰值负载小于30%的系统几乎半秒,我可以理解额外的几个ms,这很奇怪。

谢谢


考虑到问题中的日志记录调用,在计时器线程的Execute过程中,如果它们最终在同一个线程中写入日志文件,则在写入操作完成之前,它会阻塞。 由于在第一次写入操作之前检索到开始时间,因此日志间隔不仅包含等待时间( WaitForSingleObject ),还包含第一次写入操作。 这可以解释一般偏向30ms而不是20ms。 行为异常的I / O子系统或拥塞也可以解释偶尔的延长时间段。

在等待操作之前检索开始时间,但不要写入。 等待呼叫返回后写入开始和结束时间。 然后日志会更准确地反映等待时间,最有可能的是延长的延迟将会变成I / O限制。 WaitForSingleObject不太可能不准确。

另外考虑将日志写入卸载到工作线程。

链接地址: http://www.djcxy.com/p/62483.html

上一篇: WaitForSingleObject with timeout returns long after the timeout

下一篇: WaitForSingleObject and max. waiting threads