Winapi 在图形应用程序中使用计时器时的总系统冻结
我真的被这个问题困扰着,非常感谢你的建议 问题: 我们的一些用户抱怨使用我们的产品时整个系统“冻结”。无论我们如何尝试,我们都无法在任何可用于故障排除的系统中复制它 产品: 实际上,它是一个32位/64位DLL。该产品有一个自我刷新的GUI,可以绘制音频信号的实时频谱图 问题详细信息: 我从一些零碎的报告中收集到的信息如下: 当GIU打开时,有时是立即打开,有时是在GIU可见几分钟后,系统完全停止,无法使用windows操作,启动任务管理器等。键盘上没有反应,没有看到鼠标光标(或者它看到了,但对鼠标移动没有反应,我不知道)。用户必须硬重置系统才能重新启动。我认为,重要的是(在某些情况下)GIU在一段时间内是有反应的,并显示了一些适当的图片。然后这种冻结发生了。其中一份报告指出,一旦系统冻结,音频将继续呈现——即记者听到的声音(但整个窗口的图形外壳已经冻结)。注意:在这类应用程序中,它通常是一个专门的线程,负责声音处理 在Windows7 x64上,使用32位和64位版本的DLL的2个用户或多或少地被证实发生了冻结,从未听说过与此冻结相关的任何其他操作系统(尽管有1个报告没有指定任何操作系统) 这就是我收集到的全部 架构/怀疑: 我强烈怀疑GUI刷新周期是罪魁祸首 基本上,它是这样工作的:Winapi 在图形应用程序中使用计时器时的总系统冻结,winapi,timer,Winapi,Timer,我真的被这个问题困扰着,非常感谢你的建议 问题: 我们的一些用户抱怨使用我们的产品时整个系统“冻结”。无论我们如何尝试,我们都无法在任何可用于故障排除的系统中复制它 产品: 实际上,它是一个32位/64位DLL。该产品有一个自我刷新的GUI,可以绘制音频信号的实时频谱图 问题详细信息: 我从一些零碎的报告中收集到的信息如下: 当GIU打开时,有时是立即打开,有时是在GIU可见几分钟后,系统完全停止,无法使用windows操作,启动任务管理器等。键盘上没有反应,没有看到鼠标光标(或者它看到了,但对
HDC hdc = GetDC (hwnd);
// Some drawing
ReleaseDC(hwnd,hdc);
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
似乎同样适合我
事实上,在使用参考页面中提到的任何选项时,我看不出有什么重大区别
问题:
- 在
CreateTimerQueueTimer(&m\U timerHandle,NULL,xPlatformTimerCallbackWrapper,this,m\U firstExpInterval,m\U period,WT\U ExecutedDefault)中更改为WT\U ExecutedDefault代码>
- 可重入性守卫已经在那里了
- 我还没有检查在WM_PAINT hander中更新GUI是否有帮助
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毫秒后执行