本文基本是参考下面的几个博客写的,但是他们写的时候都是全篇文字,并且有的地方写的不是很详细,新手还需要自己摸索。因此,本人将自己做出来的工程一步步贴出来(只做了工作者线程的例子,用户界面线程没有做),并且会在最后上传我建立好的工程,可以自行下载参考。有写的不对的地方欢迎批评指正!
MFC中有两类线程,分别称之为工作者线程和用户界面线程。二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环。工作者线程没有消息机制,通常用来执行后台计算和维护任务,如冗长的计算过程,打印机的后台打印等。用户界面线程一般用于处理独 立于其他线程执行之外的用户输入,响应用户及系统所产生的事件和消息等。
下面开始建立工作者线程示例:
【1】首先建立一个MFC工程文件,并在界面上添加一个按钮控件、一个文本编辑框、一个进度条控件(Progress Control),并为文本编辑框关联int型变量m_e,为进度条关联CProgressCtrl型变量m_prog,界面如下:
【2】在工程文件的头文件“multiLineDlg.h”中类的外部添加一个结构体声明和一个全局函数声明,如下:
struct threadInfo
{
UINT nMilliSecond;
CProgressCtrl* pctrlProgress;
};
UINT ThreadFunc(LPVOID lpParam);
【3】在类的内部声明如下变量,此变量是线程的句柄,马上在源文件中会用到
CWinThread* pThread;
【4】在源文件“multiLineDlg.cpp”声明一个全局变量“Info”,如下,并在初始化函数“BOOL CmultiLineDlg::OnInitDialog()”中添加如下代码:
声明的全局变量
threadInfo Info;
放在初始化函数中
m_prog.SetRange(0,99); //设置进度条的范围
m_e=10; //设置文本编辑框的初始值
UpdateData(FALSE); //显示文本编辑框的值
【5】双击按钮,为其添加消息响应函数,添加如下代码,并定义刚才在头文件中声明的全局函数,代码如下:
注意:貌似下面的“AfxBeginThread”函数只能存在于一个按钮控件的最后一行,否则会出现线程交叉,可能会出现运行线程中的代码的时候,又会运行到这个“AfxBeginThread”函数下面的代码,造成乱序
按钮控件下的代码
UpdateData(TRUE);
Info.nMilliSecond=m_e;
Info.pctrlProgress=&m_prog;
pThread=AfxBeginThread(ThreadFunc, &Info); //创建MFC线程
注意:下面这个函数里面用到的变量只能是全局变量,也不能涉及到界面的一个控件的ID,否则,有可能就是不在编译的时候报错,也会在执行EXE的时候报错。
UINT ThreadFunc(LPVOID lpParam)
{
threadInfo* pInfo=(threadInfo*)lpParam;
for(int i=0;i<1000;i++)
{
int nTemp=pInfo->nMilliSecond;
pInfo->pctrlProgress->SetPos(i);
Sleep(nTemp);
}
return 0;
}
(以上只是我自己在实验时遇到的一些问题,可能是我自己研究的不透彻,如果有问题的地方,欢迎指教,谢谢!)
【6】为了体验多线程,我们为鼠标左键在界面上点击添加消息响应时间,在“类向导”或者快捷键“Ctrl+Shift+X”在消息一栏,找到“WM_LBUTTONDOWN”添加如下代码:
(可以让进度条的范围调大一些,让它跑的时间长一点,在进度条走的同时点击界面,就会弹出界面,具体效果对比在最后)
AfxMessageBox("正在进行计算");
左图是没有设置多线程,如果在跑进度条的时候,疯狂点击界面,就会导致程序假死
右图是设置了多线程的,在跑进度条的时候,点击界面,就会弹出上面设置的界面,并不会影响进度条
自己做的工程文件的链接:MFC多线程示例工程文件