四、AfxBeginThread
在介绍使用AfxBeginThread进行多线程编程之前,我们先介绍下MFC中两种线程的概念,这也是在MFC编程中无法绕过的两种类型的线程 —— 用户界面线程和工作者线程。4.1 用户界面线程
用户界面线程,顾名思义,它是一种可以管理UI界面的线程。它含有自己的消息循环,可以处理UI界面的各种消息。最常见的用户界面线程,就是MFC中主界面所在的主线程。用户界面线程可以用AfxBeginThread创建,函数原型如下:CWinThread* AfxBeginThread(
CRuntimeClass* pThreadClass,
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);
pThreadClass —— 是CWinThread类的派生类的运行时。我们要创建用户界面线程,必须定义自己的CWinThread的派生类,并重载CWinThread::InitInstance()和
WinThread::ExitInstance()函数,在CWinThread::InitInstance()我们做一些界面资源的创建和显示操作,在WinThread::ExitInstance()中我们对资源进行回收。
nPriority —— 设置线程的优先级,如果是0,设置的所有线程的优先级都一样,常见的优先级设置项参考下表:线程优先级等级 标志 优先级值
| 标志 | 优先级值 |
|
1 | idle (最低) | THREAD_PRIORITY_IDLE | 如果进程优先级为realtime则调整为16,其它情况为1 |
2 | LOWEST 低 | THREAD_PRIORITY_LOWEST | -2(在原有基础上-2) |
3 | BELOW 低于标准 | THREAD_PRIORITY_BELOW_NORMAL | -1(在原有基础上-1) |
4 | NORMAL(标准) | THREAD_PRIORITY_NORMAL | 不变(取进程优先级值) |
5 | ABOVE 高于标准 | THREAD_PRIORITY_ABOVE_NORMAL | +1(在原有基础上+1) |
6 | HIGHEST (高) | THREAD_PRIORITY_HIGHEST | +2(在原有基础上+2) |
7 | CRITICAL(最高) | THREAD_PRIORITY_TIME_CRITICAL | 如果进程优先级为realtime则调整为31,其它情况为15 |
nStackSize —— 为线程分配的调用堆栈大小,0为默认值。
dwCreateFlags —— 设置线程创建后的初始状态。0,创建后立即执行;CREATE_SUSPENDED宏,创建后被挂起。
lpSecurityAttrs —— 线程的安全属性,默认为NULL。
返回值 —— AfxBeginThread()返回的是一个CWinThread类型的指针,这是MFC中封装的一个线程类型。在MFC多线程编程中,关于线程的任何操作都是通过该类完成。
介绍完创建用户界面线程的AfxBeginThread原型之后,我们通过一个例子按照步骤介绍该函数的用法。步骤一 派生自己的CWinThread类。
通过类向导,我们从CWinThread派生一个CUIThread类,用来作为用户界面线程。类中定义一个m_udlg成员变量,为我们自定义的对话框。class CUIThread : public CWinThread
{
...
}
步骤二 创建自定义对话框
我们创建一个对话框UIDlg,并在对话框上放置一个EditControl。
然后设置一个定时器,并重载对话框的WM_TIME定时器消息处理函数,主要实现的效果是每隔1秒钟编辑框的数字会从0逐渐增大。
BOOL CMfctestDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
…
SetTimer(1,1000,NULL);
}
void UIDlg::OnTimer(UINT_PTR nIDEvent)
{
CString str;
str.Format("%d",m_index++);
this->GetDlgItem(IDC_EDIT1)->SetWindowText(str);
CDialogEx::OnTimer(nIDEvent);
}
步骤三 为CWinThread的派生了添加对话框资源以及重载相关函数
我们为CUIThread成员添加一个UIDlg类型的成员m_udlg,并重载InitInstance和ExitInstance函数:BOOL CUIThread::InitInstance()
{
m_udlg.Create(IDD_DIALOG1);//创建此ID号的对话框窗口
m_udlg.ShowWindow(SW_SHOW);
m_pMainWnd=&m_udlg;
return TRUE;
}
int CUIThread::ExitInstance()
{
m_udlg.DestroyWindow();
return CWinThread::ExitInstance();
}
步骤四 在主程序中开启用户界面线程。
我们在主程序界面添加一个按钮:
然后在按钮的点击事件处理函数中进行用户界面线程的创建:
void CMfctestDlg::OnBnClickedOpen()
{
AfxBeginThread(RUNTIME_CLASS(CUIThread));
}
如果运行程序,并点击按钮就实现了我们预期的效果:
Github位置:
https://github.com/HymanLiuTS/NetDevelopment
克隆本项目:
git clonegit@github.com:HymanLiuTS/NetDevelopment.git
获取本文源代码:
git checkout NL45