多线程编程之使用工作线程实现文档自动保存(II)

本文介绍如何在MFC程序中使用辅助工作线程实现文档自动保存,并通过Timer计时器定时触发保存操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、用辅助工作线程实现文档保存
1、线程知识

       MFC程序中的线程有两种形式:用户界面线程和辅助工作线程,本文所讲述的是辅助工作线程的添加和使用方法。
       上述两种形式的线程都是用系统全局函数AfxBeginThread添加的,该函数有两种形式。
None.gif CWinThread *  AfxBeginThread(
None.gif   AFX_THREADPROC pfnThreadProc,
None.gif   LPVOID pParam,
None.gif   
int  nPriority  =  THREAD_PRIORITY_NORMAL,
None.gif   UINT nStackSize 
=   0 ,
None.gif   DWORD dwCreateFlags 
=   0 ,
None.gif   LPSECURITY_ATTRIBUTES lpSecurityAttrs 
=  NULL 
None.gif);
None.gifCWinThread
*  AfxBeginThread(
None.gif   CRuntimeClass
*  pThreadClass,
None.gif   
int  nPriority  =  THREAD_PRIORITY_NORMAL,
None.gif   UINT nStackSize 
=   0 ,
None.gif   DWORD dwCreateFlags 
=   0 ,
None.gif   LPSECURITY_ATTRIBUTES lpSecurityAttrs 
=  NULL 
None.gif);
None.gif

2、辅助工作线程的使用
        当使用AfxBeginThread添加辅助工作线程时,我们使用第一个重载函数形式,至少需要给函数提供两个参数,第一个参数即参数表中的第一个参数,该参数是用户自己定义的工作线程处理函数的函数名;第二个参数即参数表中的第二个参数,该参数作为AfxBeginThread函数参数表中第二个参数的同时也是用户自己定义的工作线程处理函数参数表中的唯一参数,也就是说,用户自定义工作线程处理函数参数表中只含有一个LPVOID类型的参数,该参数即为AfxBeginThread函数参数表中的第二个参数。有人可能会问:如果要传递的参数多于一个怎么办?答案是:这一参数通常是一个LPVOID类型的结构(struct),而该结构所能传递的参数则是任意的。下面举出一个结构文件的例子,其中还包括辅助工作线程处理函数的声明,该函数的返回类型为UINT。这是因为:线程可以将返回值0作为线程结束的标志而使用。 为了便于理解,本代码做了简化处理。
None.gif // AutoSaveThrdProc.h
ExpandedBlockStart.gifContractedBlock.gif
/**/ ///////////////////////////////////////
None.gif // 这是辅助工作线程处理函数所要用到的结构参数的声明
None.gif

None.gif
struct  CAutoSaveThrdInfo
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif CHoopsDoc 
*pPartDoc;
InBlock.gif CHoopsView 
*pPartView;
ExpandedBlockEnd.gif}
;
None.gif
None.gifUINT AutoSaveThrdProc(LPVOID lPARAM);
        辅助工作线程处理函数的实现如下所示, 为了便于理解,本代码同样做了一些必要的简化处理。
None.gif //  AutoSaveThrdProc.cpp: implementation of the CAutoSaveThrdProc class.
None.gif

None.gif#include 
" stdafx.h "
None.gif#include 
" solid.h "
None.gif#include 
" AutoSaveThrdProc.h "
None.gif
None.gif#ifdef _DEBUG
None.gif
#undef  THIS_FILE
None.gif
static   char  THIS_FILE[] = __FILE__;
None.gif
#define  new DEBUG_NEW
None.gif
#endif
None.gif
None.gifUINT AutoSaveThrdProc(LPVOID lPARAM)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif CAutoSaveThrdInfo 
*AutoSaveThrdInfo = (CAutoSaveThrdInfo *)lPARAM;
InBlock.gif CString pathname
= "c:\\";
InBlock.gif CString filename;
InBlock.gif CHoopsDoc 
*pPartDoc = AutoSaveThrdInfo -> pPartDoc;
InBlock.gif filename 
= pPartDoc ->GetTitle();
InBlock.gif 
if(filename.Right(4)==".typ")
InBlock.gif  pathname 
+= filename;
InBlock.gif 
else
InBlock.gif  pathname 
+= filename + ".typ";
InBlock.gif pPartDoc 
-> OnSaveDocument(pathname);
InBlock.gif pPartDoc  
= NULL;
InBlock.gif 
return 0;
ExpandedBlockEnd.gif}

None.gif

3、文档保存函数的重写
        如 多线程编程之使用工作线程实现文档自动保存(I)正文以及FAQ中所述,上述OnSaveDocument函数并不是从CDocument类中继承过来的,而是Hoops(三维显示引擎)中的HoopsDoc类继承过来,并经过重写,重写后的函数原形如下所示。
None.gif BOOL CPartDoc::OnSaveDocument(LPCTSTR lpszPathName) 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    CWaitCursor cursor;
InBlock.gif
InBlock.gif    
// 检测文件是否出错
InBlock.gif
    HPartModel *pModel = (HPartModel *)m_pHoopsModel;
InBlock.gif    HPART 
*pHpart = pModel->GetHpart();
InBlock.gif
InBlock.gif    
// 找到文件名
InBlock.gif
    CString szFileName = lpszPathName;
InBlock.gif    
int nPos = szFileName.ReverseFind('\\');
InBlock.gif    
int nLength = szFileName.GetLength();
InBlock.gif    CString szTemp 
= szFileName.Right( nLength - nPos - 1 );
InBlock.gif    szTemp.SetAt(szTemp.GetLength() 
- 4,'\0');
InBlock.gif
InBlock.gif    
// Model存储相关处理
InBlock.gif         
//保存临时Modal文件
InBlock.gif
    pModel->OnSaveDocument( szTemp );
InBlock.gif
InBlock.gif    
// 结构化存储文件
InBlock.gif
    CPartFile cOpenFile(lpszPathName, CPartFile::hrFILEWRITE);
InBlock.gif    cOpenFile.SetPart(pHpart);
InBlock.gif    BOOL OK 
= cOpenFile.WritePart();
InBlock.gif
InBlock.gif    
if ( OK )
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
// 压缩文件
InBlock.gif
        CString szZipPathName(lpszPathName) ;
InBlock.gif        szZipPathName 
= szZipPathName.Left(szZipPathName.ReverseFind('.')) ;
InBlock.gif
InBlock.gif        
// getting information about the date and the attributes
InBlock.gif        
// (this is new in ZipFunc)
InBlock.gif
        CZipFile zf(szZipPathName, 0);
InBlock.gif        zip_fileinfo zi;
InBlock.gif        CFile f(lpszPathName, CFile::modeRead);
InBlock.gif        zf.UpdateZipInfo(zi, f);
InBlock.gif        zf.OpenNewFileInZip(szTemp, zi, Z_BEST_COMPRESSION);
InBlock.gif
InBlock.gif        
char buf[1024];
InBlock.gif        
int size_read;
InBlock.gif        
do
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            size_read 
= f.Read(buf, 1024);
InBlock.gif            
if (size_read)
InBlock.gif                zf.WriteInFileInZip(buf, size_read);            
ExpandedSubBlockEnd.gif        }

InBlock.gif        
while (size_read == 1024);
InBlock.gif
InBlock.gif        
// cannot be called by the destructor because it may throw an exception
InBlock.gif        
// (it is not good to throw an exception when another one may be progress)
InBlock.gif
        zf.Close();
InBlock.gif        f.Close();
InBlock.gif
InBlock.gif        
// 压缩文件覆盖掉原文件
ExpandedSubBlockStart.gifContractedSubBlock.gif
        if!CopyFile(szZipPathName,lpszPathName,FALSE) )dot.gif{
InBlock.gif            tyMessageBox(
"存储文件失败!");
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockStart.gifContractedSubBlock.gif        
elsedot.gif{
InBlock.gif            CFile::Remove(szZipPathName);
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    SetModifiedFlag( FALSE );
InBlock.gif    
return OK;
ExpandedBlockEnd.gif}
        上述代码中调用了Hoops的临时文件保存函数,该函数经过重写,与主界面线程不存在依赖关系,所以可以被辅助工作线程调用。下半部分代码则是将临时Modal文件进行压缩,并用其替换临时文件。
        为了方便初学者理解,本文省略了对于由用户操作和自动保存的并发因素造成的文档保存格式错误的解决方案,主要原因是该方案针对的是CAD系统的大规模模型的保存,不太具有普适性,对读者的帮助不大。


二、使用Timer计时器
        在这里,我们使用Timer计时器来定时触发辅助工作线程,以完成保存动作。
1、声明并设定Timer计时器
         在设定Timer计时器之前,首先要声明一个计时器成员变量,也就是给计时器取个名字,该变量应是一个由CWnd基类所派生的类(如CView类和CFrameWnd类,因为只有CWnd基类的派生类才能产生WM_TIMER系统消息)的成员变量,它要在整个类中生存,而不是某个函数内部。
        Timer计时器声明与设定形式如下:
None.gif UINT_PTR  m_nTimer;
None.gif
// 计时器时间表示以毫秒(ms)为单位
None.gif
m_nTimer  =  SetTimer(起始时间,触发时间,NULL);
        上述起始时间和触发时间之间的间隔即触发器的触发间隔,例如m_nTimer = SetTimer(0,5000,NULL)表示计时器每5秒时间间隔发送一个WM_TIMER消息。该程序中,我们将Timer计时器的声明与设定放在CPartView类的初始化函数(注意:不是构造函数)中,使得计时器在初始化CPartView对象时一同被创建。

2、捕捉WM_TIMER系统消息以触发计时器处理函数
        为已经添加Timer计时器的CWnd派生类添加WM_TIMER消息处理函数OnTimer(UINT nIDEvent),以捕捉WM_TIMER消息并处理计时器触发事件。在函数中我们要添加辅助工作线程开启代码,以实现用辅助工作线程实现文档自动保存。代码如下:
None.gif void  CPartView::OnTimer(UINT nIDEvent)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
//创建并启动自动保存工作线程
InBlock.gif
    CWinThread *pThread;
InBlock.gif    CHoopsDoc 
*pDoc = CHoopsView::GetDocument();
InBlock.gif    
if(m_bAutoSaveAllowed&&pDoc->IsModified())// &&(!m_bAutoSaveThrdExist))
ExpandedSubBlockStart.gifContractedSubBlock.gif
    dot.gif{
InBlock.gif        pThread 
= AfxBeginThread(AutoSaveThrdProc,&m_AutoSaveThrdInfo);
InBlock.gif        m_bAutoSaveThrdExist 
= TRUE;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    CHoopsView::OnTimer(nIDEvent);
InBlock.gif
ExpandedBlockEnd.gif}

3、关闭Timer计时器与重设Timer计时器
        当用户进行定制,改变自动保存的间隔时间时,就需要关闭现有计时器,并重设一个Timer计时器。要关闭计时器,使用KillTimer(m_nTimer)函数即可,其中的m_nTimer为想要关掉的计时器变量。相关代码如下:
None.gif LRESULT CPartView::OnResetTimer(WPARAM wPARAM, LPARAM lPARAM)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    KillTimer(m_nTimer);
InBlock.gif    m_nTimer 
= CHoopsView::SetTimer(1,m_AutoSaveInterval,NULL);
InBlock.gif    
return LRESULT();
ExpandedBlockEnd.gif}



三、总结与展望
        本文中,对辅助工作线程的使用方法和Timer计时器的使用方法做了一些简要的介绍,所举代码并不是完整的程序代码,虽不能独立运行,但足以说明上述技术的使用原理与方法,不足之处还望读者见谅,并与我讨论!

        为了彻底解决多线程之间对同一资源的同步使用所出现的冲突问题,我将在下一篇文章中讲解如何使用线程同步类来实现文档的多线程自动保存。敬请关注! 

转载于:https://www.cnblogs.com/antoniozhou/archive/2006/08/17/478840.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值