利用MFC可以创建两种线程,分别称之为工作线程和用户界面线程。二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环。工作者线程没有消息机制,通常用来执行后台计算和维护任务,如冗长的计算过程,打印机的后台打印等。用户界面线程一般用于处理独立于其他线程执行之外的用户输入,响应用户及系统所产生的事件和消息等。
工作线程的创建
创建工作线程分为三步:(1)线程函数的声明(2)线程函数的实现(3)创建(启动)线程
(1)线程函数的声明:
线程函数的声明必须在类外声明,格式如下:
UINT ThreadFunc(LPVOID lpParam);返回类型及LPVOID不能改变。
(2)线程函数的定义:
UINT ThreadFunc(LPVOID lParam)
{
while(true){
AfxMesageBox("子线程");
Sleep(1000);
}
}
(3)线程函数的创建(启动)
创建线程有两种方式:
1)一般直接用AfxBeginThread(ThreadProc,this);
void CITTDlg::OnKMeansSegment() //按钮点击执行
{
AfxBeginThread(ThreadFunc, (LPVOID)this);//启动新的线程
}
2)首先创建CWinThread类的一个对象,然后调用该对象的成员函数CreateThread()来启动该线程。
用户界面线程
由于用户界面线程含有自己的消息循环,可以处理Windows消息,并可创建和管理诸如窗口和控件等用户界面元素。因此,这种线程较工作线程更为复杂。
创建用户界面线程的起点是从MFC的CWinThread类派生一个定制的线程类,而不是调用AfxBeginThead()函数。定制的线程类必须重载InitInstance()函数,该函数用来执行初始化任务,在创建线程时系统将调用InitInstance()函数。最好还要重载ExitInstane()函数,该函数是InitInstance()函数的对应,MFC在删除线程对象之前会调用ExitInstane()函数,以便线程能够在结束后清除自身。
用户界面线程的创建有两种方法,方法一是首先从CWinThread类派生一个类(必须要用宏DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE对该类进行声明和实现),然后调用AfxBeginThead()创建CWinThread派生类的对象进行初始化,启动线程运行。方法二是先通过构造函数创建类CWinThread的一个对象,然后由程序员调用函数::CreateThread来启动线程。通常CWinThread类的对象在该线程的生存期结束时将自动终止,如果程序员希望自己来控制,则需要将m_bAutoDelete设为FALSE。这样在线程终止之后,CWinThread类对象仍然存在,此时需要手动删除CWinThread对象。
用户界面线程的实现:
1.先建一个mfc界面(类为:testThread),在界面放置一按钮。
2.右键属性,添加类,选择MFC类,点击添加,选择基类为CWinThread,填写类名,如:CUIThread,自动生成UIThread.h和UIThread.cpp
3.给工程添加新界面IDD_UITHREADDLG,标题为“线程对话框”。 对界面改为IDD_UITHREADDLG,双击该界面创建一个基于CDialog的类CUIThreadDlg,包含CUIThreadDlg.h和CUIThreadDlg.cpp
4.在IDD_UITHREADDLG界面放置一按钮,双击进入函数,
void CUIThreadDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
AfxMessageBox("You Clicked The Left Button!");
CDialog::OnLButtonDown(nFlags, point);
}
5.在UIThread.h中添加
#include "UIThreadDlg.h"
并在CUIThread类中添加protected变量
CUIThreadDlg m_dlg;
6.分别重载InitInstance()函数和ExitInstance()函数:
BOOL CUIThread::InitInstance()
{
m_dlg.Create(IDD_UITHREADDLG);
m_dlg.ShowWindow(SW_SHOW);
m_pMainWnd=&m_dlg;
return TRUE;
}
int CUIThread::ExitInstance()
{
m_dlg.DestroyWindow();
return CWinThread::ExitInstance();
}
7.在主界面双击“用户界面线程”按钮按钮,进入函数添加消息响应函数:
在CtestThreadDlg.cpp的开头添加:#include “UIThread.h”
void CtestThreadDlg::OnUiThread()
{
CWinThread *pThread=AfxBeginThread(RUNTIME_CLASS(CUIThread));
}
每单击一次主界面的“用户界面线程”按钮,都会弹出一个线程对话框,在任何一个线程对话框内按下鼠标左键,都会弹出一个消息框。
如果不想弹出界面,则在线程函数中实现想实现的线程功能。
1.先建一个mfc界面(类为:testThread),在界面放置一按钮。
2.右键属性,添加类,选择MFC类,点击添加,选择基类为CWinThread,填写类名,如:CUIThread,自动生成UIThread.h和UIThread.cpp
3.在UIThread.h的类内声明一个线程函数,函数名自定,我的类中的线程函数叫StartThread
UIThread.h:
#ifndef T_THREAD_H
#define T_THREAD_H
#pragma once
#define WM_TEST WM_USER + 105 //定义线程函数入口地址
class CUIThread: public CWinThread
{
DECLARE_DYNCREATE(MyThread)
public:
MyThread();
virtual BOOL InitInstance();
virtual int ExitInstance();
void StartThread(WPARAM wParam, LPARAM lParam);//线程函数
DECLARE_MESSAGE_MAP();
};
#endif
4.UIThread.cpp:实现线程函数StartThread
首先先重写
BOOL InitInstance();
int ExitInstance();
两个函数的定义后,在定义线程函数时加上下面的语句
BEGIN_MESSAGE_MAP(MyThread, CWinThread)
ON_THREAD_MESSAGE(WM_TEST, StartThread)
END_MESSAGE_MAP()
这三条代码的作用是将线程消息传递路由定义好,接受到WM_TEST信号,则跳转到函数StartThread,执行该函数。
void CUIThread::StartThread(WPARAM wParam, LPARAM lParam)
{
while (true)
{
AfxMessageBox("子线程");
Sleep(1000);
}
}
然后在主线程的按键消息函数中开启线程,开启线程的方式是先声明定义一个线程类指针
MyThread* p_MyThread;
再用AfxBeginThread获得线程指针
void CtestThreadDlg::OnBnClickedOk()
{
// TODO: 在此添加控件通知处理程序代码
p_MyThread= (MyThread*)AfxBeginThread(RUNTIME_CLASS(CUIThread), );
p_MyThread->ResumeThread();//启动线程
p_MyThread->PostThreadMessage(WM_TEST, 15, NULL);//发送WM_TEST消息
}
5.子线程也可以向主线程发送消息:
在子线程的UIThread.h中添加
#define WM_MESSAGEWM_USER+200//向主线程发送消息,用于返回相关信息
在UIThread.cpp中发送该消息
void CUIThread::StartThread(WPARAM wParam, LPARAM lParam)
{
wParam++;
if(wParam<20)
{
AfxMessageBox("OK");
Sleep(1000);
}
else{
AfxMessageBox("NO");
::SendMessage(AfxGetMainWnd()->m_hWnd,,WM_MESSAGE,0,0);//向主线程发送消息
}
}
6.主线程接受消息,并执行相关函数。
在MFC类向导中为CtestThreadDlg类添加消息,点击添加自定义消息,添加UIThread.h发送的消息名字WM_MESSAGE,点击确定,自动生成消息响应函数。
afx_msg LRESULT CtestThreadDlg::OnMessage(WPARAM wParam,LPARAM lParam)
{
AfxMessageBox("主函数接收到子线程发送的消息");
}
598

被折叠的 条评论
为什么被折叠?



