C++ 打开大文件 我有一个单文档接口(SDI)微软基础类(MFC)应用程序,它必须加载一个大文档文件(大约需要2分钟)。因此,当我打开文档时,我的应用程序保持无响应

C++ 打开大文件 我有一个单文档接口(SDI)微软基础类(MFC)应用程序,它必须加载一个大文档文件(大约需要2分钟)。因此,当我打开文档时,我的应用程序保持无响应,c++,mfc,C++,Mfc,但是,我希望我的应用程序在打开文档时能够做出响应。问题是,如果我尝试在线程上加载文档,则在我实际打开文档之前,我的OnopenDocument函数(在我的文档中)将返回: BOOL CmodguiDoc::OnOpenDocument(LPCTSTR lpszPathName) { if (!CDocument::OnOpenDocument(lpszPathName)) return FALSE; start_tread(_open_doc); // just an examp

但是,我希望我的应用程序在打开文档时能够做出响应。问题是,如果我尝试在线程上加载文档,则在我实际打开文档之前,我的
OnopenDocument
函数(在我的文档中)将返回:

BOOL CmodguiDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
  if (!CDocument::OnOpenDocument(lpszPathName))
    return FALSE;
  start_tread(_open_doc); // just an example
  return TRUE; // Will return before the document will actually be open
}
我如何做到不锁定,但仅在文档实际打开后返回?或者,在加载文档时,我如何至少使我的应用程序响应


谢谢

创建线程后返回即可。您应该定义文档的状态,例如
加载
加载
。启动线程时,状态应为加载。视图应查看状态并相应显示。当线程加载完文档后,它应该向文档发布一条消息。在处理程序中,将状态设置为
loaded
,并调用
updatealviews()
,使视图有机会使用新文档数据进行更新

示例:这将在加载文档时打印“加载”,并在视图中完成加载后打印“加载”

在资源.h中:

#define IDD_NotifyDocumentFinished        101
在文档标题中:

public:
   enum DocState
   {
      None,
      Failed,
      Loading,
      Loaded
   };

   DocState GetDocState() const {return m_state;}
private:
   DocState m_state;
   void StartLoading();
在执行文件中:

BOOL CMFCDocViewAsyncDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
   if(!CDocument::OnOpenDocument(lpszPathName))
      return FALSE;   

   m_state = Loading;

   StartLoading();

   return TRUE;
}

UINT LongRunningFunction(LPVOID param)
{
   Sleep(3000);

   HWND hWnd = AfxGetApp()->m_pMainWnd->GetSafeHwnd();

   NMHDR hdr = {hWnd, IDD_NotifyDocumentFinished, 0};
   ::SendMessage(hWnd, WM_NOTIFY, 0, reinterpret_cast<LPARAM>(&hdr));

   return 0;
}

void CMFCDocViewAsyncDoc::StartLoading()
{
   AfxBeginThread(&LongRunningFunction, nullptr);
}

BOOL CMFCDocViewAsyncDoc::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
   if(HIWORD(nCode) == WM_NOTIFY)
   {
      WORD wCode = LOWORD(nCode);
      AFX_NOTIFY * notify = reinterpret_cast<AFX_NOTIFY*>(pExtra);
      if(notify->pNMHDR->idFrom == IDD_NotifyDocumentFinished)
      {
         m_state = Loaded;
         UpdateAllViews(nullptr);
      }
   }

   return TRUE;
}

更新:这里还有一个类似的更详细的例子。

当只需两分钟就可以加载某个内容时,有两个原因:

  • 加载时您正在做一些愚蠢的事情,例如对数据运行昂贵的算法,如索引或图形渲染。如果将数据存储在容器中,分配的开销也会变得很大。如果是这种情况,则只能按需执行这些操作,或者在后台异步执行这些操作。例如,您可以在完成时通知主线程(运行UI的线程),以便显示渲染的图形
  • 数据非常大。在这种情况下,您将不得不重新考虑如何访问这些数据,因为任何操作都可能非常昂贵。最好使用异步模型,比如向模型发送请求以执行某些操作。然后,模型向UI发送响应以显示数据。在这种情况下,您需要考虑如何使其对用户透明。一种方法是在更改请求后使显示区域变暗,并仅在响应或进度条后使其变亮

  • 您不能希望线程同时阻塞并继续执行。除非你买了一台昂贵的量子计算机。@I不可检测,这就是为什么我要找一个替代体系结构的原因。替代方案是将文件名存储在你的
    onpendendocument
    回调中,并按需加载数据。您不能在GUI线程上等待加载操作运行完成并同时为其他消息提供服务。在加载文档之前,您必须以这样或那样的方式返回。如果您的应用程序准备处理可重入性问题,您也可以定期从文档加载程序调用,以在GUI线程上服务消息。谢谢,但您能否更具体一些?如何定义文档状态?还有一个问题。我无法从线程获取文档句柄,我无法从线程更新状态不是从线程更新,而是在线程发布的消息的处理程序中更新。另一个问题,文档数据何时设置?e、 g.带有项目名称的窗口标题?我的项目文件由一个可扩展到2gb的唯一文件组成
    void CMFCDocViewAsyncView::OnDraw(CDC* pDC)
    {
        CMFCDocViewAsyncDoc* pDoc = GetDocument();
        ASSERT_VALID(pDoc);
        if (!pDoc)
            return;
    
        CMFCDocViewAsyncDoc::DocState state = pDoc->GetDocState();
       CString sstate;
       switch(state)
       {
       case CMFCDocViewAsyncDoc::None:
          sstate = "None";
          break;
       case CMFCDocViewAsyncDoc::Failed:
          sstate = "Failed";
          break;
       case CMFCDocViewAsyncDoc::Loading:
          sstate = "Loading";
          break;
       case CMFCDocViewAsyncDoc::Loaded:
          sstate = "Loaded";
          break;
       }
       pDC->TextOut(50, 50, sstate);
    }