MFC 多线程编程

17 篇文章 3 订阅
5 篇文章 0 订阅

MFC 多线程概述

MFC中有两类线程 , 分别称之为工作者线程和用户界面线程 ;
二者的主要区别在于 工作者线程没有消息循环 , 而用户界面线程有自己的消息队列和消息循环 ;

  • 工作者线程没有消息机制 , 通常用来执行后台计算和维护任务 , 如冗长的计算过程 , 打印机的后台打印等 ;
  • 用户界面线程一般用于处理独立于其他线程执行之外的用户输入 , 响应用户及系统所产生的事件和消息等 ;

但对于 Win32 的 API 编程而言 , 这两种线程是没有区别的 , 它们都只需线程的启动地址即可启动线程来执行任务 ;


MFC 多线程 API 支持

在MFC中 , 一般用全局函数 AfxBeginThread() 来创建并初始化一个线程的运行 , 该函数有两种重载形式 , 分别用于创建工作者线程和用户界面线程 (UI 线程) ; 两种重载函数原型和参数分别说明如下 :

工作者线程
CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,
	LPVOID pParam,
	nPriority=THREAD_PRIORITY_NORMAL,
	UINT nStackSize=0,
	DWORD dwCreateFlags=0,
	LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);

其中各参数说明如下 :

pfnThreadProc : 指向工作者线程的执行函数的指针 , 线程函数原型必须声明如 : UINT ExecutingFunction(LPVOID pParam); , 请注意 , ExecutingFunction() 应返回一个 UINT 类型的值 , 用以指明该函数结束的原因 , 一般情况下 , 返回 0 表明执行成功 ;
pParam : 传递给线程函数的一个 32 位参数 , 执行函数将用某种方式解释该值 , 它可以是数值 , 或是指向一个结构的指针 , 甚至可以被忽略 ;
nPriority : 线程的优先级 , 如果为 0 , 则线程与其父线程具有相同的优先级 ;
nStackSize : 线程为自己分配堆栈的大小 , 其单位为字节 ; 如果 nStackSize 被设为 0 , 则线程的堆栈被设置成与父线程堆栈相同大小 ;
dwCreateFlags : 如果为 0 , 则线程在创建后立刻开始执行 ; 如果为 CREATE_SUSPEND , 则线程在创建后立刻被挂起 ;
lpSecurityAttrs : 线程的安全属性指针 , 一般为 NULL ;

用户界面线程
CWinThread* AfxBeginThread(CRuntimeClass* pThreadClass,
	int nPriority=THREAD_PRIORITY_NORMAL,
	UINT nStackSize=0,
	DWORD dwCreateFlags=0,
	LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);

其中各参数说明如下 :

pThreadClass : 指向 CWinThread 的一个导出类的运行时类对象的指针 , 该导出类定义了被创建的用户界面线程的启动 , 退出等 ;
其它参数的意义同工作者线程类似 ;
使用函数的这个原型生成的线程也有消息机制 , 在以后的例子中我们将发现同主线程的机制几乎一样 ;

CWinThread 类

CWinThread 类的 数据成员 简要说明如下 :

`m_hThread` : 当前线程的句柄 ;  
`m_nThreadID` : 当前线程的ID ;  
`m_pMainWnd` : 指向应用程序主窗口的指针 ;

CWinThread 类的 常用函数 简要说明如下 :

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

该函数中的 dwCreateFlags , nStackSize , lpSecurityAttrs 参数和 API 函数 CreateThread 中的对应参数有相同含义 , 该函数执行成功 , 返回非 0 值 , 否则返回 0 ;
一般情况下 , 调用 AfxBeginThread(); 来一次性地创建并启动一个线程 , 但是也可以通过两步法来创建线程 : 首先创建 CWinThread 类的一个对象 , 然后调用该对象的成员函数 CreateThread(); 来启动该线程 ;

virtual BOOL CWinThread::InitInstance();

重载该函数以控制用户界面线程实例的初始化 ; 初始化成功则返回非 0 值 , 否则返回 0 ; 用户界面线程经常重载该函数 , 工作者线程一般不使用该函数函数 ;

virtual int CWinThread::ExitInstance();

在线程终结前重载该函数进行一些必要的清理工作 ; 该函数返回线程的退出码 , 0 表示执行成功 , 非 0 值用来标识各种错误 ; 同 InitInstance(); 成员函数一样 , 该函数也只适用于用户界面线程 ;


MFC 创建多线程实例

MFC 创建工作者线程代码如下 :

新建一个 MFC 对话框项目 , 在对话框头文件定义一个工作者线程函数 , 如下 :

static UINT WorkerThreadFunc(LPVOID lpParam);

源文件实现如下 (这里让工作者线程等待一秒左右时间模拟数据处理) :

UINT CMFCWorkerThreadDlg::WorkerThreadFunc(LPVOID lpParam)
{
	for(int nIndex=0; nIndex<100; nIndex++)
	{
		// Do Something
		Sleep(10);
	}
	return 0;
}

创建工作者线程代码如下 :

void CMFCWorkerThreadDlg::OnBnClickedButtonStart()
{	
	CWinThread* pThread;
	// 启动工作者线程
	pThread=AfxBeginThread(WorkerThreadFunc, &Info);
	// 阻塞等待工作者线程结束
	WaitForSingleObject(pThread->m_hThread, INFINITE);
	pThread = NULL;
}
MFC 创建UI线程代码如下 :

创建 CWinThread 的派生类 CUIThread :

// UIThread.h 文件
#pragma once
class CUIThread : public CWinThread
{
	DECLARE_DYNCREATE(CUIThread)
protected:
	CUIThread();    // 动态创建所使用的受保护的构造函数
	virtual ~CUIThread();
public:
	virtual BOOL InitInstance();
	virtual int ExitInstance();
protected:
	DECLARE_MESSAGE_MAP()
};

重载函数 InitInstance();ExitInstance(); :

// UIThread.cpp 文件
#include "stdafx.h"
#include "UIThread.h"
IMPLEMENT_DYNCREATE(CUIThread, CWinThread)
CUIThread::CUIThread()
{
}
CUIThread::~CUIThread()
{
}
BOOL CUIThread::InitInstance()
{
	CFrameWnd* pWnd=new CFrameWnd;
	pWnd->Create(NULL, _T("UI Thread Window"));
	pWnd->ShowWindow(SW_SHOW);
	pWnd->UpdateWindow();
	m_pMainWnd=pWnd;    // 这个语句必须要有
	return TRUE;
}
int CUIThread::ExitInstance()
{
	return CWinThread::ExitInstance();
}
BEGIN_MESSAGE_MAP(CUIThread, CWinThread)
END_MESSAGE_MAP()

在主对话框启动 UI 线程 :

void CMainDlg::OnBnClickedStartUI()
{
	CWinThread *pUIThread = AfxBeginThread(RUNTIME_CLASS(CUIThread));
}

作者 Github : tojohnonly , 博客 : EnskDeCode

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值