CWinThread

CWinThread类是MFC用来封装线程的,包括UI线程和工作者线程。 

因此每个MFC程序至少使用一个CWinThread派生类。被MFC程序员熟知的CWinApp应用类就从这里派生。 Windows以消息驱动方式工作,每个WIN32应用程序都至少包含一个消息队列和一个消息泵。消息队列建立在操作系统提供内存保留区中,消息泵不断搜寻消息队列,将取得的消息分发给应用程序的各个部分进行处理,这个过程叫做消息循环

       基本消息循环如下:

 //从队列中获取消息

  while(GetMessage(&msg,0,0,0)) 

{

 //转换消息参数

 TranslateMesssage(&msg); 

//分发消息 DispatchMessage(&msg);

 } 

Windows以线程封装消息循环,封装消息循环的线程叫做用户界面线程,即UI线程。该线程可以创建并撤销窗口。此外,还有一种线程叫做工作者线程,它是辅助UI线程工作的,它没有消息循环,不能处理系统事件和窗口消息,也不能关联主窗口。主线程和辅线程虽然享有共同的虚拟地址空间,但各自占用独立的CPU时间片,参与系统资源的竞争。所以,可以使用辅线程完成经常性的、耗费机时的数据处理工作(例如网络通信),减轻UI线程的负担,确保UI线程及时响应用户的窗口操作。

       根据需要,一个应用程序中也可以创建多个UI线程。 


      下面介绍几个实用的CWinThread类成员函数。 

      虚函数InitInstance Windows允许同时运行一个应用程序的多个备份,又称为运行一个程序的多个实例。InitInstance就是“初始化实例”的意思,可见,它是在实例创建时首先被调用的。应用程序总要重载这个虚函数,进行系统设置,创建运行环境。例如,主窗口一定要在InitInstance()中创建,因为该函数退出后就进入该线程的消息循环。 

      虚函数Run 该函数提供UI线程的消息循环,即反复地提取消息,分发消息,直到收到WM_QUIT退出循环,线程随即结束。在循环中,如果当前没有收到消息,则调用空闲消息处理程序OnIdle() 。以下是该函数的完整定义。  

virtual int CWinThread::Run() { ASSERT_VALID(this); //是否要做空闲处理 BOOL bIdle = TRUE; //用户记录空闲处理已经连接执行的次数 LONG lIdleCount = 0; //acquire and dispatch messages until a WM_QUIT message is received. //消息循环 for (;;) { //如果空闲状态为真,且消息队列为空,则进行空闲处理 while(bIdle && !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)) { //PeekMessage()用于检查消息队列是否为空,但并不处理消息 //调用空闲处理程序,如果返回零,说明空闲处理已全部完成 if (!OnIdle(lIdleCount++)) bIdle = FALSE; } //空闲处理循环结束,进入消息泵循环 do { //调用消息泵,提取消息并分发消息 //如果收到WM_QUIT消息,则退出消息循环 if (!PumpMessage()) return ExitInstance(); //根据刚处理的消息类型,判断是否应该在没有消息到来时立即进行空闲处理 if (IsIdleMessage(&m_msgCur)) { bIdle = TRUE; //在重新进行空闲处理前,清空空闲处理的执行次数 lIdleCount = 0; } } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)); } ASSERT(FALSE); //不可能执行的语句 } /*------------- 消息泵函数PumpMessage() ----------------*/ //省略了调试信息的输出功能 BOOL CWinThread::PumpMessage() { ASSERT_VALID(this); //取出消息队列中的第一个消息,直到取得消息,该函数才返回 if (!::GetMessage(&m_msgCur, NULL, NULL, NULL)) { //收到WM_QUIT消息 return FALSE; } //处理消息,但不处理WM_KICKIDLE if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur)) { //转换虚键消息到字符消息 ::TranslateMessage(&m_msgCur); //分发消息 ::DispatchMessage(&m_msgCur); } return TRUE; }

 

//RUN 函数调用消息幚PumpMessage 循环处理消息。    

       阅读PumpMessage代码可知,消息泵并不处理WM_KICKIDLE消息,收到该消息后,直接返回。其实,WM_KICKIDLE消息被用来刺激空闲处理的执行,它作为一个空消息促使::GetMessage()返回。 虽然Run()是虚拟函数,但很少被重载。   虚函数ExitInstance 与InitInstance()相反,该函数是在退出消息循环时执行,一般被框架调用,做最后的清理工作。但如果调用InitInstance()失败,ExitInstance()也会被调用。可以重载ExitInstance(),为线程做相关的清理工作。不要在除重载的Run()函数外的地方调用它。如果将CWinThread成员变量m_bAutoDelete设为TRUE,CWinThread::ExitInstance()会删除当前的CWinThread对象。所以,如果在堆栈中构造了UI线程对象,可以利用默认的ExitInstance()自动将它删除。  

CWinThread的使用

常见的启动线程函数有三个:  
  CreateThread(),   _beginThread(以及_beginThreadEx()),AfxBeginThread()  
  1和2是sdk函数,3是mfc函数  
  至于启动的是工作者线程还是UI线程,是由函数3的参数来决定的 ;

一个例子:

 

class CUIThread : public CWinThread 
{
	DECLARE_DYNCREATE(CUIThread) 
protected: CUIThread(); // protected constructor used by dynamic creation 
		   // Attributes 
public: // Operations 
public: // Overrides 
	// ClassWizard generated virtual function overrides 
	//{{AFX_VIRTUAL(CUIThread) 
public: 
	virtual BOOL InitInstance(); 
	virtual int ExitInstance(); 
	//}}AFX_VIRTUAL 
	// Implementation 
protected: 
	virtual ~CUIThread(); 
	// Generated message map functions 
	//{{AFX_MSG(CUIThread) 
	// NOTE - the ClassWizard will add and remove member functions here. 
	//}}AFX_MSG DECLARE_MESSAGE_MAP() 
}; 

//重载函数InitInstance()和ExitInstance() 
BOOL CUIThread::InitInstance() 
{
	CFrameWnd* wnd=new CFrameWnd;
	wnd->Create(NULL,"UI Thread Window");
	wnd->ShowWindow(SW_SHOW); 
	wnd->UpdateWindow();
	m_pMainWnd=wnd; 
	return TRUE; 
} 


//创建新的用户界面线程 
void CUIThreadDlg::OnButton1() 
{ 
	CUIThread* pThread=new CUIThread(); 
	pThread->CreateThread();
}


请注意以下两点:

1.在UIThreadDlg.cpp的开头加入语句: #include "UIThread.h"
2.把UIThread.h中类CUIThread()的构造函数的特性由 protected 改为 public。
  用户界面线程的执行次序与应用程序主线程相同,首先调用用户界面线程类的InitInstance()函数,如果返回TRUE,继续调用线程的 Run()函数,该函数的作用是运行一个标准的消息循环,并且当收到WM_QUIT消息后中断,在消息循环过程中,Run()函数检测到线程空闲时(没有消息),也将调用OnIdle()函数,最后Run()函数返回,MFC调用ExitInstance()函数清理资源。
  你可以创建一个没有界面而有消息循环的线程,例如:你可以从CWinThread派生一个新类,在InitInstance函数中完成某项任务并返回FALSE,这表示仅执行InitInstance函数中的任务而不执行消息循环,你可以通过这种方法,完成一个工作者线程的功能。

 

另一个例子:

//.Cpp 文件   
#include "stdafx.h"   
#include "TestThread.h"   

IMPLEMENT_DYNCREATE(CTestThread, CWinThread)  

CTestThread::CTestThread()  
{  
}  

CTestThread::~CTestThread()  
{  
}  

BEGIN_MESSAGE_MAP(CTestThread, CWinThread)  
	ON_THREAD_MESSAGE(WM_TEST,OnTest)  
END_MESSAGE_MAP()  

BOOL CTestThread::InitInstance()  
{  
	return TRUE;  
}  

int CTestThread::ExitInstance()  
{  
	return CWinThread::ExitInstance();  
}  

void CTestThread::OnTest(WPARAM wParam,LPARAM lParam)  
{  
	AfxMessageBox("test");  
}  

//调用的地方   
CWinThread* m_pThrd;  
//启动   
m_pThrd = AfxBeginThread(RUNTIME_CLASS(CTestThread));  
// 需要执行线程中的操作时   
m_pThrd->PostThreadMessage(WM_TEST,NULL,NULL);  

// 结束线程   
HANDLE hp=m_pThrd->m_hThread;  
if (hp)   
{  
	if (WaitForSingleObject(hp, 1) != WAIT_OBJECT_0)  
	{  
		TerminateThread(hp,0);  
	}  
	CloseHandle(hp);  
} 


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值