技术开发 频道

使用工作线程实现文档自动保存

IT168 技术文档】

    最近正在忙着开发一款三维CAD系统。BOSS希望该CAD系统具备文档自动保存功能,就像Office系列软件一样,在用户不知不觉的情况下将其所作修改进行保存,这样可以防止在意外宕机情况下用户的操作丢失。

    其实添加自动保存功能并不是一件非常困难的事情,最简单的情况就是设置Timer计时器,捕捉系统消息WM_TIMER,并在Timer的响应函数里调用CDocument::OnSaveDocument()函数,使用主线程进行文档保存。不过,这样做是有弊端的。例如在我们所要做的CAD系统中,在实际使用过程中,可能会出现数据量非常庞大的零部件或组装结构。如果在这种情况下使用主线程来保存文档,文档的保存时间可能会较长。而在文档保存的过程中,系统会将光标设置为等待,因此,不仅无法再对文档进行操作,即使能操作,也会因为主线程正在忙碌状态而使系统无法响应用户操作,势必影响使用。

    一个较好的方法就是使用辅助工作线程来进行文档的保存工作。由于工作线程只在后台运行,与主线程相对独立,因此,可以较好地解决用户操作与文档保存的并行问题。虽然在单核CPU情况下,所谓的多线程仍然存在CPU使用上的等待与交替过程,但由系统强制分配的CPU使用时间保证了两种操作形式上的并行,基本上解决了问题。

    另外需要强调的是,由于MFC类库中的CDocument类在使用过程中,其内部函数与主线程存在线程依赖关系。具体是由一个Map影射造成的,因此如果使用传递给工作线程处理函数的CDocument类型指针直接调用CDocument::OnSaveDocument()则会造成程序断言失败而意外退出。下面是windows核心代码wincore.cpp内部包含的一个原函数。

void CWnd::AssertValid() const { if (m_hWnd == NULL) return; // null (unattached) windows are valid // check for special wnd??? values ASSERT(HWND_TOP == NULL); // same as desktop if (m_hWnd == HWND_BOTTOM) ASSERT(this == &CWnd::wndBottom); else if (m_hWnd == HWND_TOPMOST) ASSERT(this == &CWnd::wndTopMost); else if (m_hWnd == HWND_NOTOPMOST) ASSERT(this == &CWnd::wndNoTopMost); else { // should be a normal window ASSERT(::IsWindow(m_hWnd)); // should also be in the permanent or temporary handle map CHandleMap* pMap = afxMapHWND(); ASSERT(pMap != NULL); CObject* p; ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL || (p = pMap->LookupTemporary(m_hWnd)) != NULL); ASSERT((CWnd*)p == this); // must be us // Note: if either of the above asserts fire and you are // writing a multithreaded application, it is likely that // you have passed a C++ object from one thread to another // and have used that object in a way that was not intended. // (only simple inline wrapper functions should be used) // // In general, CWnd objects should be passed by HWND from // one thread to another. The receiving thread can wrap // the HWND with a CWnd object by using CWnd::FromHandle. // // It is dangerous to pass C++ objects from one thread to // another, unless the objects are designed to be used in // such a manner. } }

    注意看上述代码的注释部分。由于CDocument::OnSaveDocument()函数进行了较高层封装,与线程相关,因此,CDocument::OnSaveDocument()函数需要重写。在重写的过程中,不能再继承CDocument::OnSaveDocument()函数,而需要从更低层着手写保存操作。

0
相关文章