Winapi 在图形应用程序中使用计时器时的总系统冻结

Winapi 在图形应用程序中使用计时器时的总系统冻结,winapi,timer,Winapi,Timer,我真的被这个问题困扰着,非常感谢你的建议 问题: 我们的一些用户抱怨使用我们的产品时整个系统“冻结”。无论我们如何尝试,我们都无法在任何可用于故障排除的系统中复制它 产品: 实际上,它是一个32位/64位DLL。该产品有一个自我刷新的GUI,可以绘制音频信号的实时频谱图 问题详细信息: 我从一些零碎的报告中收集到的信息如下: 当GIU打开时,有时是立即打开,有时是在GIU可见几分钟后,系统完全停止,无法使用windows操作,启动任务管理器等。键盘上没有反应,没有看到鼠标光标(或者它看到了,但对

我真的被这个问题困扰着,非常感谢你的建议

问题: 我们的一些用户抱怨使用我们的产品时整个系统“冻结”。无论我们如何尝试,我们都无法在任何可用于故障排除的系统中复制它

产品: 实际上,它是一个32位/64位DLL。该产品有一个自我刷新的GUI,可以绘制音频信号的实时频谱图

问题详细信息: 我从一些零碎的报告中收集到的信息如下:

当GIU打开时,有时是立即打开,有时是在GIU可见几分钟后,系统完全停止,无法使用windows操作,启动任务管理器等。键盘上没有反应,没有看到鼠标光标(或者它看到了,但对鼠标移动没有反应,我不知道)。用户必须硬重置系统才能重新启动。我认为,重要的是(在某些情况下)GIU在一段时间内是有反应的,并显示了一些适当的图片。然后这种冻结发生了。其中一份报告指出,一旦系统冻结,音频将继续呈现——即记者听到的声音(但整个窗口的图形外壳已经冻结)。注意:在这类应用程序中,它通常是一个专门的线程,负责声音处理

在Windows7 x64上,使用32位和64位版本的DLL的2个用户或多或少地被证实发生了冻结,从未听说过与此冻结相关的任何其他操作系统(尽管有1个报告没有指定任何操作系统)

这就是我收集到的全部

架构/怀疑:

我强烈怀疑GUI刷新周期是罪魁祸首

基本上,它是这样工作的:

HDC hdc = GetDC (hwnd);
// Some drawing
ReleaseDC(hwnd,hdc);
  • 有一个计时器以大约25 fps的帧速率触发回调
  • 在此回调中,将执行音频分析并更新GUI
  • 有关计时器的一些详细信息:

    这是基于这个电话:

    CreateTimerQueueTimer(&m_timerHandle, NULL, xPlatformTimerCallbackWrapper,
           this, m_firstExpInterval, m_period, WT_EXECUTEINTIMERTHREAD);
    
    我们创建一个计时器,并定期调用
    m_timer handle

    有关GUI刷新的一些详细信息:

    它的工作原理如下:

    HDC hdc = GetDC (hwnd);
    // Some drawing
    ReleaseDC(hwnd,hdc);
    
    我的直觉告诉我,这个
    CreateTimeQueueTimer
    可能不是正确的决定。说明在使用
    WT_EXECUTEINTIMERTHREAD
    的情况下:

    回调函数由计时器线程本身调用。这面旗 应仅用于短期任务或 它可能会影响其他计时器 操作。回调函数是 作为APC排队。不应该 执行可报警的等待操作

    我不记得为什么选择这个
    WT_EXECUTEINTIMERTHREAD
    选项,实际上,现在
    WT_EXECUTEDEFAULT
    似乎同样适合我

    事实上,在使用参考页面中提到的任何选项时,我看不出有什么重大区别

    问题:

  • 被告知的任何事情是否能给任何人提供可能出错的线索
  • 你有没有遇到过类似的问题,原因是什么
  • 谢谢你提供的任何信息

    ========================================== 更新:2010-02-20

    不幸的是,这里给出的建议(我可以查到目前为止)没有帮助,具体如下:

    • CreateTimerQueueTimer(&m\U timerHandle,NULL,xPlatformTimerCallbackWrapper,this,m\U firstExpInterval,m\U period,WT\U ExecutedDefault)中更改为WT\U ExecutedDefault
    • 可重入性守卫已经在那里了
    • 我还没有检查在WM_PAINT hander中更新GUI是否有帮助
    无论如何,谢谢你的提示

    现在,我已经玩了一段时间,还得到了一个真正的W7安装(我曾经使用虚拟的),似乎问题可以缩小

    在我的安装中,使用该应用程序确实使GUI的响应性大大降低,尽管我无法像有人报告的那样再现整个系统的冻结

    我现在的假设是,这种反应性下降和报告的完全冻结有一个共同的起源

    然后我做了一些原始的分析,发现至少有一个罪魁祸首是BitBlt函数,它每秒被调用大约50次

    BitBlt ((HDC)pContext->getSystemContext (),  // hdcDest
                    destRect.left + pContext->offset.h, 
                    destRect.top + pContext->offset.v,  
                    destRect.right - destRect.left,    
                    destRect.bottom - destRect.top,    
    
                    (HDC)pSystemContext,                
                    srcOffset.h,                    
                    srcOffset.v,           
                    SRCCOPY);           
    
    要复制的区域不是很大(约400x200像素)。它用于显示backbuffer,并在计时器回调中执行

    如果我对这个BitBlt调用进行注释,问题似乎消失了(至少部分消失)

    在运行WinXP的同一台机器上,一切正常


    对此有什么想法吗?

    最可能发生的情况是,计时器回调的执行时间超过了25毫秒。然后另一个计时器滴答声出现,它也开始处理。诸如此类,很快你就会有一大堆线程在消耗CPU周期,所有的线程都在尝试做音频分析,很快系统就会忙着做线程上下文切换,以至于没有真正的工作完成。与此同时,越来越多的计时器信号被放入队列中

    我强烈建议您在这里使用
    WT\u EXECUTEDEFAULT
    ,而不是
    WT\u EXECUTEINTIMERTHREAD
    。此外,还需要防止重叠的计时器回调。有几种方法可以做到这一点

    您可以在计时器回调中使用关键部分。当回调被触发时,它调用
    tryenterCriticalSection
    ,如果不成功,只返回而不执行任何操作

    您可以使用
    volatile
    变量和
    InterlocatedCompareExchange
    执行类似操作

    或者,您可以将计时器更改为一次性(
    WT_executeonce
    ),然后在每次回调结束时重新设置计时器。这将使事情在最后一次事件发生25毫秒后执行