【问题标题】:Progress bar in MFC UI Thread is blockedMFC UI 线程中的进度条被阻止
【发布时间】:2011-12-19 19:27:53
【问题描述】:

对于工作中的 MFC 项目,我必须在单独的 UI 线程 (CWinThread) 中创建进度条对话框 (CProgressCtrl)。我从网站http://adilevin.wordpress.com/2009/06/29/user-interface-threads-in-mfc/ 中举了一个例子。它自己工作。 (基本上,它有两个进度条,一个来自主 gui 线程,一个在单独的 ui 线程中创建。示例演示了在主 gui 线程中执行的计算不会干扰在 ui 线程中创建的进度条)

但是当我将代码放入我的应用程序时,进度条卡在了对 CProgressCtrl 的 SetPos 调用中。当我冻结主线程时(在它运行计算时),我从 Visual Studio 得到消息

进程似乎已死锁(或未运行任何用户模式 代码)。所有线程都已停止。

所以看起来 UI 线程正在等待来自主线程的东西?但我不知道它在等什么。这是卡住的ui线程的调用堆栈。

user32.dll!GetPropW()  + 0x72 bytes 
[Frames below may be incorrect and/or missing, no symbols loaded for user32.dll]    
user32.dll!SendMessageW()  + 0x4c bytes 
uxtheme.dll!DrawThemeParentBackgroundEx()  + 0x114 bytes    
comctl32.dll!GetEffectiveClientRect()  + 0x28f0 bytes   
comctl32.dll!GetEffectiveClientRect()  + 0x2916 bytes   
comctl32.dll!GetEffectiveClientRect()  + 0x2af3 bytes   
comctl32.dll!GetEffectiveClientRect()  + 0x2a25 bytes   
comctl32.dll!GetEffectiveClientRect()  + 0x2992 bytes   
user32.dll!gapfnScSendMessage()  + 0x270 bytes  
user32.dll!gapfnScSendMessage()  + 0x922 bytes  
user32.dll!FillRect()  + 0x110 bytes    
user32.dll!CallWindowProcA()  + 0x1b bytes  
mfc100d.dll!CWnd::DefWindowProcA(unsigned int nMsg=15, unsigned int wParam=0, long lParam=0)  Line 1089 + 0x20 bytes    C++
mfc100d.dll!CWnd::WindowProc(unsigned int message=15, unsigned int wParam=0, long lParam=0)  Line 2088 + 0x1c bytes C++
mfc100d.dll!AfxCallWndProc(CWnd * pWnd=0x08156d68, HWND__ * hWnd=0x00012452, unsigned int nMsg=15, unsigned int wParam=0, long lParam=0)  Line 257 + 0x1c bytes C++
mfc100d.dll!AfxWndProc(HWND__ * hWnd=0x00012452, unsigned int nMsg=15, unsigned int wParam=0, long lParam=0)  Line 420  C++
cv32.dll!AfxWndProcDllStatic(HWND__ * hWnd=0x00012452, unsigned int nMsg=15, unsigned int wParam=0, long lParam=0)  Line 54 + 0x15 bytes    C++
user32.dll!gapfnScSendMessage()  + 0x270 bytes  
user32.dll!GetDC()  + 0x52 bytes    
user32.dll!GetWindowLongW()  + 0x18a bytes  
user32.dll!GetDC()  + 0xab bytes    
ntdll.dll!KiUserCallbackDispatcher()  + 0x2e bytes  
comctl32.dll!GetEffectiveClientRect()  + 0x2660 bytes   
comctl32.dll!RegisterClassNameW()  + 0x37e bytes    
user32.dll!gapfnScSendMessage()  + 0x270 bytes  
user32.dll!gapfnScSendMessage()  + 0x922 bytes  
user32.dll!FillRect()  + 0x110 bytes    
user32.dll!CallWindowProcA()  + 0x1b bytes  
mfc100d.dll!CWnd::DefWindowProcA(unsigned int nMsg=1026, unsigned int wParam=65, long lParam=0)  Line 1089 + 0x20 bytes C++
mfc100d.dll!CWnd::WindowProc(unsigned int message=1026, unsigned int wParam=65, long lParam=0)  Line 2088 + 0x1c bytes  C++
mfc100d.dll!AfxCallWndProc(CWnd * pWnd=0x08156d68, HWND__ * hWnd=0x00012452, unsigned int nMsg=1026, unsigned int wParam=65, long lParam=0)  Line 257 + 0x1c bytes  C++
mfc100d.dll!AfxWndProc(HWND__ * hWnd=0x00012452, unsigned int nMsg=1026, unsigned int wParam=65, long lParam=0)  Line 420   C++
cv32.dll!AfxWndProcDllStatic(HWND__ * hWnd=0x00012452, unsigned int nMsg=1026, unsigned int wParam=65, long lParam=0)  Line 54 + 0x15 bytes C++
user32.dll!gapfnScSendMessage()  + 0x270 bytes  
user32.dll!gapfnScSendMessage()  + 0x922 bytes  
user32.dll!GetWindow()  + 0x21a bytes   
user32.dll!SendMessageA()  + 0x4c bytes 
mfc100d.dll!CProgressCtrl::SetPos(int nPos=65)  Line 363 + 0x46 bytes   C++
cv32.dll!CProgressCtrlWithTimer::OnTimer(unsigned int nIDEvent=1)  Line 1577    C++

有人知道什么是错的吗?

当我自己运行示例应用程序时,它不会调用 uxtheme.dll,因为它没有在示例中使用。最后一个 SendMessageW 可能是问题吗?

【问题讨论】:

  • 您确定您的 OnTimer 事件没有在 UI 线程上执行吗?我遇到过一些案例,Visual Studio 试图通过将计时器事件发布到 UI 线程上来“让它更容易”,而不是让我手动委派它......
  • 您似乎正在尝试从后台线程更新 UI。但是由于您冻结了 UI 线程,它无法响应,并且您创建了一个死锁。在后台线程上进行计算,而不是 UI 线程。

标签: c++ multithreading mfc progress-bar deadlock


【解决方案1】:

SetPos 表示对 SendMessage 的调用,这是一个阻塞调用。您必须绝不跨线程边界调用SendMessage,因为这注定会导致死锁。

如果需要更新主线程上运行的GUI,必须使用PostMessage

PostMessage(hWndMain, UWM_MYMESSAGE, progress, 0);

并在主线程中处理消息:

LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam)
{
   m_progress.SetPos((int)wParam);
   return 1;
}

【讨论】:

  • 这样可以避免死锁,但是进度条仍然不会更新,因为OP在UI线程上进行计算,所以它不是在检索消息。
  • 是的,我的主线程正在进行计算,因此无法更新 UI。 (我希望我可以在工作线程中完成这项工作,但这在我正在从事的项目中是不可能的)。我正在更新在单独的 UI 线程(不是主 ui 线程)中创建的进度条。我不明白那个分离的 ui 线程中的 SetPos 是如何被主线程阻塞的。
猜你喜欢
  • 1970-01-01
  • 2015-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多