【问题标题】:Create a dialog in UI Thread causes crash在 UI 线程中创建对话框导致崩溃
【发布时间】:2010-10-06 13:42:52
【问题描述】:

我试图在 UI 线程 (CWinThread) 中创建一个对话框。 但是,当调用 CDialog::Create() 时它会崩溃。 我用之前的实现验证过,对话框是在非线程模式下成功创建的。

这里有高手知道在CWinThread中创建对话框的崩溃原因吗?

无线程:

class CProduction : public CDialog{
...
}
class CScrollProductionView : public CScrollView{
CProduction *m_pProduction;
...
}

void CScrollProductionView::OnInitialUpdate(){
   m_pProduction = new CProduction(0, *m_pVisionAdapter);
   m_pProduction->Create(IDD_DLG_PROD, this);  //--> created dialog successfully
   m_pProduction->ShowWindow(SW_SHOW);
}

实现 UI 线程:

class CProduction : public CDialog{
...
}
class CScrollProductionView : public CScrollView{
  CProductionThread* m_pProdThread;
  ...
}

class CProductionThread : public CWinThread{
   CProduction *m_pProduction;
   ...
}

void CScrollProductionView::OnInitialUpdate(){
   m_pProdThread->PostThreadMessage(WM_INITPRODTHREADMESSAGE, PROD_INIT, (LPARAM)m_pVisionAdapter);
   m_pProdThread->PostThreadMessage(WM_INITPRODTHREADMESSAGE, PROD_CREATE_DLG, (LPARAM)this);

 }

void CProductionThread::InitMessageHandler(WPARAM wParam, LPARAM lParam)
{
   printf("Receiving InitMessageHandler msg %d\n", (UINT)wParam);
   switch(wParam)
   {
    case PROD_INIT:
    {
      CVisionAdapter* pAdapter = (CVisionAdapter*)lParam;
      m_pProduction = new CProduction(NULL, *pAdapter);
    }
     break;
    case PROD_CREATE_DLG:
     {
      CScrollProductionView* pView = (CScrollProductionView*)lParam;
      m_pProduction->Create(IDD_DLG_PROD, pView);  //--> Crash here
      m_pProduction->ShowWindow(SW_SHOW);
     }
       break;
     default:
       break;
   }
}

错误信息:

调试断言失败! ..
文件: .... wincore.cpp
线路:9906

感谢您查看此问题。

【问题讨论】:

  • 你的 wincore.cpp 第 9906 行的断言是什么?断言代码本身或附近的注释通常会提供关于问题所在的重要线索。

标签: c++ multithreading


【解决方案1】:

尽量不要创建 CWinThread,而是创建一个工作线程,如果你在类之间有很多通信,比如传递对象指针、字符串等。
如果通过消息处理更新 GUI,您将不会感到头疼。

【讨论】:

    【解决方案2】:

    我怀疑问题是在处理PROD_CREATE_DLG 消息时尚未创建您的CProduction 对象。这可能是因为使用了PostThreadMessage。使用PostThreadMessage 充满了问题。特别是,消息可能会丢失,因此线程永远不会看到PROD_INIT 消息。

    在单线程代码中,您在 Create 调用之前创建您的 CProduction 对象。为什么不在多线程代码中做同样的事情?

    如果您真的想使用 Windows 消息在线程之间进行通信,我将创建一个“仅消息”窗口(参见 http://msdn.microsoft.com/en-us/library/ms632599.aspx#message_only),因为窗口消息不会像线程消息那样丢失做。

    或者,使用线程安全队列在线程之间传递自定义消息,例如我在http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html 的示例队列

    【讨论】:

      【解决方案3】:

      崩溃是由 MFC 在创建过程中引用无效窗口句柄(作为父级传入)引起的。

      作为一般规则,线程可以访问 只有它创建的 MFC 对象。这个 是因为暂时的和永久的 Windows 句柄映射保存在线程中 本地存储以帮助维护 防止同时访问 来自多个线程。

      http://msdn.microsoft.com/en-us/library/h14y172e(VS.71).aspx

      MSDN 中所述的一个简单修复方法是将代码更改为

      ...
      
      m_pProdThread->PostThreadMessage(WM_INITPRODTHREADMESSAGE, PROD_CREATE_DLG, (LPARAM)this->GetSafeHwnd());
      
      ...
      
      CScrollProductionView* pView = (CScrollProductionView*)CScrollProductionView::FromHandle((HWND)lParam);
      m_pProduction->Create(IDD_DLG_PROD, pView);
      m_pProduction->ShowWindow(SW_SHOW);
      

      编辑
      修复了 msdn 的链接。

      【讨论】:

      • “如果您有一个多线程应用程序,它以不同于使用 CWinThread 对象的方式创建线程,则您无法从该线程访问其他 MFC 对象...”来自msdn.microsoft.com/en-us/library/h14y172e(v=VS.90).aspx
      • @wengseng,结果如何?我能够模拟我这边的崩溃,这是在发布修改后修复的。
      猜你喜欢
      • 1970-01-01
      • 2012-05-22
      • 2014-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-27
      • 1970-01-01
      相关资源
      最近更新 更多