使用适配器模式实现工作线程的应用程序框架

考虑这样一个需求:当客户在终端数据导入界面选择需要导入的文件,点击导入后,终端会通过FTP上传导入的数据,如果上传文件很大很多,耗时很长,客户感觉会非常不好。主要是因为UI线程被阻塞,不再响应窗口消息,给客户的感觉终端像死掉一样,而客户也不知道上传文件的进度,所以希望终端提供进度条来显示上传的进度。

这是一个用户界面编程的经典问题,这个问题的一种解决方案是使用多线程,通过把FTP上传导入的工作委派给一个工作线程来处理,UI线程在调用函数启动工作线程后,自动返回。

工作线程在运行过程中不断向UI线程发送更新消息,UI线程把工作线程的工作进度显示在界面上,这样进度条的显示将是一个真实的工作进度,而不是一个虚假的进度。当工作线程完成任务后,会向UI线程发送一个结束任务的消息,UI线程在收到消息后,进行一些收尾工作。

因为这个问题是一个通用问题,我们考虑设计一个工作线程的应用程序框架。我们的设计目标是把工作线程的启动,结束和终止操作,以及工作线程与UI线程的通讯等繁琐操作封装在应用程序框架中,而把线程实现的具体业务逻辑与之分类开来,让工作线程的代码尽量的得到复用。让应用程序框架的使用者把精力主要集中于具体业务逻辑的实现。

具体的实现我采用了Adapter模式,使用其中的组合实现方式,并且运用了Policy技术(Modern C++ Design所提出的泛型设计技术)。

下图是类结构图:

 

这样,在CWorkThread模板类中的svc函数中,会在循环中调用函数对象的operator()运算符,因此用户只要实现一个包括operator()运算符的类,处理具体的业务就可以了。

当然用户还需要编写代码,处理工作线程为进度条和窗口所发的消息,进行相应的界面更新处理,和线程结束处理工作。

通过CWorkThread模板类把线程类CWorkThreadBase类和函数对象的工作结合起来,CWorkThread模板类实际上是一个适配器,这样就实现了工作线程框架。

具体代码如下:

 

const UINT WM_USER_THREAD_UPDATE    =       WM_USER+0x101; //线程进度更新消息

const UINT WM_USER_THREAD_FINISHED  = WM_USER+0x102; //线程完成消息

const UINT WM_USER_THREAD_ABORTED   =     WM_USER+0x103; //线程废止消息

 

class CWorkThreadBase

{

public:

       CWorkThreadBase(HWND hWnd = NULL);

       virtual ~CWorkThreadBase(void);

 

protected:

       HWND m_hWnd;//接收消息的窗口的句柄,句柄在线程间传递是安全的

       BOOL m_bWorking;//线程是否工作

       HANDLE m_hWorkThread;   // 工作线程句柄。

       HANDLE m_hEvent;

 

public:

       int BeginThread(string& sError);

       void KillThread(void);

       int ThreadFinished(void);

       bool IsWork(void){return m_bWorking;}

private:

    static unsigned __stdcall WorkThreadFunc(void* pParam);

       virtual int svc() = 0;

};

 

int GetOSError(string& sError);

 

CWorkThreadBase::CWorkThreadBase(HWND hWnd)

       :m_hWnd(hWnd)

{

       m_bWorking = FALSE;

       m_hWorkThread = NULL;

       m_hEvent = CreateEvent(NULL,

                                             TRUE,//手工reset

                                             FALSE, //未通知状态

                                             NULL);

}

 

CWorkThreadBase::~CWorkThreadBase(void)

{

}

 

int CWorkThreadBase::BeginThread(string& sError)

{

       if(m_bWorking)

       {

        sError = "The thread is still working!";

              return OP_FAULT;

       }

 

       m_bWorking = TRUE;

       ResetEvent (m_hEvent);

       unsigned uThreadID;

 

       //启动工作线程,调用WorkThreadFunc函数

       unsigned long res = _beginthreadex (

                                                 NULL,// security

                                                 0,//stack_size

                                                 CWorkThreadBase::WorkThreadFunc,

                                                 this,

                                                 CREATE_SUSPENDED,

                                                 &uThreadID);

       if(res == 0)

       {

              GetOSError(sError);

              return OP_FAULT;

    }

 

       m_hWorkThread = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME,

                                                    FALSE,

                                                    uThreadID);

       if(m_hWorkThread == NULL)

       {

              GetOSError(sError);

              return OP_FAULT;

    }

 

       int rv = ResumeThread (m_hWorkThread);

       if(rv <0)

       {

              GetOSError(sError);

              return OP_FAULT;

       }

       else if(rv >1)

       {

              sError = "The thread is still suspended!";

              return rv;

       }

 

       return OP_SUCCESS;

}

 

void CWorkThreadBase::KillThread(void)

{

       //杀死线程

       if(m_bWorking)

       {

              SetEvent(m_hEvent);

       }

}

 

int CWorkThreadBase::ThreadFinished(void)

{

       if(m_hWorkThread != NULL)

       {

        //等待线程彻底停止

              ::WaitForSingleObject(m_hWorkThread, INFINITE);

              CloseHandle (m_hWorkThread);

       }

 

       CloseHandle (m_hEvent);

       m_hWorkThread = NULL;

       m_bWorking = FALSE;//注意,只有在线程彻底停止后才设置FALSE

       return OP_SUCCESS;

}

 

unsigned __stdcall CWorkThreadBase::WorkThreadFunc(void* pParam)

{

       CWorkThreadBase* pThread = (CWorkThreadBase*)pParam;

       //接收消息的窗口句柄

       HWND hWnd                     = pThread->m_hWnd;

 

       int rv = 0  ;

       try

       {

              rv = pThread->svc();

       }

       catch(...)

       {

              rv = OP_FAULT;

       }

 

       bool bAorted = (WaitForSingleObject(pThread->m_hEvent, 0)

                                      == WAIT_OBJECT_0);

 

       //发消息通知消息窗口,线程已经结束

       if(IsWindow(hWnd) && !bAorted)

       {

              ::PostMessage(hWnd, WM_USER_THREAD_FINISHED,(WPARAM)rv,(LPARAM)pThread);

       }

 

       return (unsigned) rv;

}

 

int GetOSError(string& sError)

{

       DWORD dwError = ::GetLastError();

       HLOCAL hlocal = NULL;   // Buffer that gets the error message string

       BOOL bResult = ::FormatMessage(

              FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,

              NULL, dwError, 0, (PTSTR) &hlocal, 0, NULL);

 

       if (!bResult)

       {

              // Is it a network-related error?

              HMODULE hDll = ::LoadLibraryEx(TEXT("netmsg.dll"), NULL,

                     DONT_RESOLVE_DLL_REFERENCES);

 

              if (hDll != NULL)

              {

                     ::FormatMessage(

                            FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM,

                            hDll, dwError, 0, (PTSTR) &hlocal, 0, NULL);

                     ::FreeLibrary(hDll);

              }

       }

 

       if (hlocal != NULL)

       {

              sError =  (PCTSTR) ::LocalLock(hlocal);

              ::LocalFree(hlocal);

              return OP_SUCCESS;

       }

       else

       {

              return OP_FAULT;

       }

}

 

template <class Functor,

                class Container = vector<string> >

class CWorkThread : public CWorkThreadBase

{

public:

       CWorkThread(const Functor& func,

                   HWND hwnd = NULL,

                            HWND hStatus = NULL)

              :CWorkThreadBase(hwnd),

               func_(func),

         hStatusWnd_(hStatus)

       {}

 

       virtual ~CWorkThread(void)

       {}

 

       void refreshContainer(const Container& cont)

       {

              cont_.clear();

              cont_.insert(cont_.begin(),cont.begin(),cont.end());

       }

 

protected:

       virtual int svc()

       {

              int rv = 0;

              size_t iTotalNums = cont_.size();

              Container::const_iterator cit = cont_.begin();

              for(size_t iCurrentNums =1;

                     cit != cont_.end(); ++cit,++iCurrentNums)

              {

                     string sUpdateInfo;

                     rv = func_(*cit,sUpdateInfo);

                     if(rv != 0)

                     {

                            break;

                     }

 

                     //如果事件对象被触发,则终止线程

                     if(WaitForSingleObject (m_hEvent, 0) == WAIT_OBJECT_0

                            && IsWindow(m_hWnd))

                     {

                            //发消息通知窗口,线程已经终止

                            ::PostMessage(m_hWnd, WM_USER_THREAD_ABORTED,

                                                   (WPARAM)-1,(LPARAM)this);

                            return -1;

                     }

 

                     //发消息通知更新进度条的显示

                     if(IsWindow(hStatusWnd_))

                     {

                            ::SendMessage(hStatusWnd_, WM_USER_THREAD_UPDATE,

                                                   (WPARAM)iCurrentNums,

                                                   (LPARAM)iTotalNums);

                     }

 

                     if(!sUpdateInfo.empty())

                     {

                            updateInfo(sUpdateInfo);//用于客户显示额外的更新信息

                     }

              }

              return rv;

       }

 

       virtual void updateInfo (const string& sUpdateInfo)

       {

        if(IsWindow(m_hWnd))

              {

                     SendMessage(m_hWnd, WM_USER_THREAD_UPDATE,

                                          (WPARAM)sUpdateInfo.c_str(),

                                       (LPARAM)0);

              }

    }

private:

       Container  cont_;

       Functor   func_;

       HWND    hStatusWnd_;//进度条的窗口句柄

};

 

参考文献:

1         《设计模式-可复用面向对象软件的基础》(Design Patterns - Elements of Reusable Object-Oriented Software

2         C++设计新思维——泛型编程与设计模式之应用》(Modern C++ Design ——Generic Programming and Design Patterns Applied

3         Windows核心编程》

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值