深入浅出Win32多线程设计之MFC的多线程(1)

1、创建和终止线程

  在MFC 程序中创建一个线程,宜调用AfxBeginThread函数。该函数因参数不同而具有两种重载版本,分别对应工作者线程和用户接口(UI)线程。

  工作者线程

CWinThread *AfxBeginThread(
 AFX_THREADPROC pfnThreadProc, //控制函数
 LPVOID pParam, //传递给控制函数的参数
 int nPriority = THREAD_PRIORITY_NORMAL, //线程的优先级
 UINT nStackSize = 0, //线程的堆栈大小
 DWORD dwCreateFlags = 0, //线程的创建标志
 LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL //线程的安全属性
);

  工作者线程编程较为简单,只需编写线程控制函数和启动线程即可。下面的代码给出了定义一个控制函数和启动它的过程:

//线程控制函数
UINT MfcThreadProc(LPVOID lpParam)
{
 CExampleClass *lpObject = (CExampleClass*)lpParam;
 if (lpObject == NULL || !lpObject->IsKindof(RUNTIME_CLASS(CExampleClass)))
  return - 1; //输入参数非法
 //线程成功启动
 while (1)
 {
  ...//
 }
 return 0;
}

//在MFC程序中启动线程
AfxBeginThread(MfcThreadProc, lpObject);

  UI线程

  创建用户界面线程时,必须首先从CWinThread 派生类,并使用 DECLARE_DYNCREATE 和 IMPLEMENT_DYNCREATE 宏声明此类。

  下面给出了CWinThread类的原型(添加了关于其重要函数功能和是否需要被继承类重载的注释):

class CWinThread : public CCmdTarget
{
 DECLARE_DYNAMIC(CWinThread)

 public:
  // Constructors
  CWinThread();
  BOOL CreateThread(DWORD dwCreateFlags = 0, UINT nStackSize = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);

  // Attributes
  CWnd* m_pMainWnd; // main window (usually same AfxGetApp()->m_pMainWnd)
  CWnd* m_pActiveWnd; // active main window (may not be m_pMainWnd)
  BOOL m_bAutoDelete; // enables 'delete this' after thread termination

  // only valid while running
  HANDLE m_hThread; // this thread's HANDLE
  operator HANDLE() const;
  DWORD m_nThreadID; // this thread's ID

  int GetThreadPriority();
  BOOL SetThreadPriority(int nPriority);

  // Operations
  DWORD SuspendThread();
  DWORD ResumeThread();
  BOOL PostThreadMessage(UINT message, WPARAM wParam, LPARAM lParam);

  // Overridables
  //执行线程实例初始化,必须重写
  virtual BOOL InitInstance();

  // running and idle processing
  //控制线程的函数,包含消息泵,一般不重写
  virtual int Run();

  //消息调度到TranslateMessage和DispatchMessage之前对其进行筛选,
  //通常不重写
  virtual BOOL PreTranslateMessage(MSG* pMsg);

  virtual BOOL PumpMessage(); // low level message pump

  //执行线程特定的闲置时间处理,通常不重写
  virtual BOOL OnIdle(LONG lCount); // return TRUE if more idle processing
  virtual BOOL IsIdleMessage(MSG* pMsg); // checks for special messages

  //线程终止时执行清除,通常需要重写
  virtual int ExitInstance(); // default will 'delete this'

  //截获由线程的消息和命令处理程序引发的未处理异常,通常不重写
  virtual LRESULT ProcessWndProcException(CException* e, const MSG* pMsg);

  // Advanced: handling messages sent to message filter hook
  virtual BOOL ProcessMessageFilter(int code, LPMSG lpMsg);

  // Advanced: virtual access to m_pMainWnd
  virtual CWnd* GetMainWnd();

  // Implementation
 public:
  virtual ~CWinThread();
  #ifdef _DEBUG
   virtual void AssertValid() const;
   virtual void Dump(CDumpContext& dc) const;
   int m_nDisablePumpCount; // Diagnostic trap to detect illegal re-entrancy
  #endif
  void CommonConstruct();
  virtual void Delete();
  // 'delete this' only if m_bAutoDelete == TRUE

  // message pump for Run
  MSG m_msgCur; // current message

 public:
  // constructor used by implementation of AfxBeginThread
  CWinThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam);

  // valid after construction
  LPVOID m_pThreadParams; // generic parameters passed to starting function
  AFX_THREADPROC m_pfnThreadProc;

  // set after OLE is initialized
  void (AFXAPI* m_lpfnOleTermOrFreeLib)(BOOL, BOOL);
  COleMessageFilter* m_pMessageFilter;

 protected:
  CPoint m_ptCursorLast; // last mouse position
  UINT m_nMsgLast; // last mouse message
  BOOL DispatchThreadMessageEx(MSG* msg); // helper
  void DispatchThreadMessage(MSG* msg); // obsolete
};

  启动UI线程的AfxBeginThread函数的原型为:

CWinThread *AfxBeginThread(
 //从CWinThread派生的类的 RUNTIME_CLASS
 CRuntimeClass *pThreadClass,
 int nPriority = THREAD_PRIORITY_NORMAL,
 UINT nStackSize = 0,
 DWORD dwCreateFlags = 0,
 LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);

  我们可以方便地使用VC++ 6.0类向导定义一个继承自CWinThread的用户线程类。下面给出产生我们自定义的CWinThread子类CMyUIThread的方法。

  打开VC++ 6.0类向导,在如下窗口中选择Base Class类为CWinThread,输入子类名为CMyUIThread,点击"OK"按钮后就产生了类CMyUIThread。

深入浅出Win32多线程设计之MFC的多线程(1)_第1张图片

  其源代码框架为:

/////////////////////////////////////////////////////////////////////////////
// CMyUIThread thread

class CMyUIThread : public CWinThread
{
 DECLARE_DYNCREATE(CMyUIThread)
 protected:
  CMyUIThread(); // protected constructor used by dynamic creation

  // Attributes
 public:

  // Operations
 public:

  // Overrides
  // ClassWizard generated virtual function overrides
  //{{AFX_VIRTUAL(CMyUIThread)
  public:
   virtual BOOL InitInstance();
   virtual int ExitInstance();
  //}}AFX_VIRTUAL

  // Implementation
 protected:
  virtual ~CMyUIThread();

  // Generated message map functions
  //{{AFX_MSG(CMyUIThread)
   // NOTE - the ClassWizard will add and remove member functions here.
  //}}AFX_MSG

 DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////
// CMyUIThread

IMPLEMENT_DYNCREATE(CMyUIThread, CWinThread)

CMyUIThread::CMyUIThread()
{}

CMyUIThread::~CMyUIThread()
{}

BOOL CMyUIThread::InitInstance()
{
 // TODO: perform and per-thread initialization here
 return TRUE;
}

int CMyUIThread::ExitInstance()
{
 // TODO: perform any per-thread cleanup here
 return CWinThread::ExitInstance();
}

BEGIN_MESSAGE_MAP(CMyUIThread, CWinThread)
//{{AFX_MSG_MAP(CMyUIThread)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

  使用下列代码就可以启动这个UI线程:

CMyUIThread *pThread;
pThread = (CMyUIThread*)
AfxBeginThread( RUNTIME_CLASS(CMyUIThread) );

  另外,我们也可以不用AfxBeginThread 创建线程,而是分如下两步完成:

  (1)调用线程类的构造函数创建一个线程对象;

  (2)调用CWinThread::CreateThread函数来启动该线程。

  在线程自身内调用AfxEndThread函数可以终止该线程:

void AfxEndThread(
 UINT nExitCode //the exit code of the thread
);

  对于UI线程而言,如果消息队列中放入了WM_QUIT消息,将结束线程。

  关于UI线程和工作者线程的分配,最好的做法是:将所有与UI相关的操作放入主线程,其它的纯粹的运算工作交给独立的数个工作者线程。

  候捷先生早些时间喜欢为MDI程序的每个窗口创建一个线程,他后来澄清了这个错误。因为如果为MDI程序的每个窗口都单独创建一个线程,在窗口进行切换的时候,将进行线程的上下文切换! 

你可能感兴趣的:(深入浅出Win32多线程设计之MFC的多线程(1))