实验9多线程程序设计.docx
《实验9多线程程序设计.docx》由会员分享,可在线阅读,更多相关《实验9多线程程序设计.docx(13页珍藏版)》请在冰豆网上搜索。
实验9多线程程序设计
实验九多线程程序设计
'、实验目的
1、工作线程的创建;
2、多线程的创建;
3、主程序与线程间数据交换;
4、线程工作状态设置及修改。
】、实验要求
2.1创建一个窗口,建立子菜单(创建线程(BEGIN_THREAD)、线程关闭(CLOSE)),利用创建线程BEGIN_THREAD,创建许多工作线程,利用线程关闭(CLOSE)所有线程。
每个工作线程都对全局变量intgl_i加100,然
后在线程中判别全局变量BOOLgl_bclose,当判别为线程结束时,将当前线程获得的gl_i在对话中显示(即中间对话中显示的值)。
注意,由于线程是一个简单的延时后累加的过程,所有随着控制线程是否结
束的时间不同,得到的值是不相同的。
控制线程结束,利用线程关闭(CLOSE)实现对gl_bclose的修改。
2.2同1,要求利用子菜单选择同时启动两个线程,在这两个线程中分别有各自的累加值并在线程中对其进行累加,不过要求两个线程有不同的优先级别,当线程关闭后,显示两线程当前的累计值。
2.3编写一个线程,功能是将主程序通过利用参数传递方法传递给线程的一个整型数(或一个类)定时累加。
建立一个对话窗口,有线程的‘启动’、’挂起’/‘运行’和‘停止’三个按钮,’启动按钮’实现启动一个线程,’挂起’/‘运行’是一个按钮,是根据当前线程的状态设置,显然当线程在’运行’状况,该按钮应该显示‘挂起’,反之,显示‘运行’,当按该按钮后,使线程处于挂起状态或运行状态,’停止’按钮显然是停止该线程的运行。
另有一个
‘MOVE按钮和一个编辑控件,按‘MOVIE按钮将当前线程中的整型值在编辑控件上显示。
目的:
了解线程与主程序间的参数传递。
三、实验过程
3.1首先创建单文档工程,如下图:
3.2第一部分一线程的创建与结束:
3.2.1添加全局变量:
intgl_i;//计数
BOOLgl_bclose;
//线程控制:
true-结束所有线程;false-线程继续执行
3.2.2线程的创建:
线程靠一个CWinThread类的对象来管理,启动一个新线程的方法很
简单,用到API函数的AfxBeginThread,定义如下:
CWinThread*AFXAPIAfxBeginThread
(AFX_THREADPROCpfnThreadProc,//线程函数的地址
LPVOIDpParam,//传送到线程函数的参数
intnPriority,//(可选的)线程的优先级,默认的是
平常的优先级,
UINTnStackSize,//(可选的)线程的堆栈大小
DWORDdwCreateFlags,//(可选的)如果用户创建的线
程在开始的时候在挂起态,而不在运行态,可以设置为
CREATE_SUSPENDED
LPSECURITY_ATTRIBUTESIpSecurityAttrs
//(可选的)线程的安全属性,默认的是和父线程的访问权限一样
);
函数AfxBeginThread启动新线程并返回一个线程对象指针,然后,
新线程和启动新线程的线程同时运行。
函数的第一个参数指定线程函数。
新线程首先执行这个函数,在这个函数中可以再调用其他函数完成新线程的工作,这个
函数执行完毕返回时,新线程结束。
线程函数不能是任意定义,必须定义如下:
UINTThreadFunction(LPVOIDpParam);
这个函数必须被定义成全局函数,函数的返回类型必须是UINT,必须有一
个LPVOID类型的参数,这个参数一般使用AfxBeginThread函数的第二
个参数pParam。
函数的返回值在函数中任意定义(但不能返回特殊值STILL_AVTIVE,它被定义成0X00000I03L,表示线程仍在运行,引起混淆)。
AfxBeginThread函数的具体用法可查阅MSDN。
3.2.3线程函数:
线程函数定义了线程要做什么,在进入这个函数的时候线程开始,退出的时候线程结束。
这个函数称为线程函数,定义如下:
UINTThreadFunction(LPVOIDpParam);
这里:
ThreadFunction是线程函数名,就是启动线程函数的第一个参数
pfnThreadProc。
参数LPVOIDpParam是启动线程函数的第二个参数,该参数是一个32位数,是在线程对象创建时传送给对象的构造函数。
线程函数根据需要进行对参数进行处理,实际上,线程和主程序之间可以利用这个参数实现数据传递。
3.2.4终止线程:
线程终止由两种方法,一种是等待线程函数执行完毕后自动退出,线程退出后创建的线程对象是否自动删除,是由CWinThread对象的一个成员变量
m_bAutoDelete决定,为TRUE时,线程执行后自动删除创建的CWinThread
对象,否则,在线程结束后,该对象并不删除,需要外部来删除
可以在线程创建后对m_bAutoDelete设置
如:
m_pDrawThread->m_bAutoDelete=FALSE;
这样,在线程执行结束后并不删除,需要外部去删除:
deletem_pDrawThread;
另一个终止线程的方法是调用MFC函数AfxEndThread:
voidAFXAPIAfxEndThread(UINTnExitCode,BOOLbDelete);延时计数可利用函数:
VOIDSleep(
DWORDdwMilliseconds//延时长度(单位:
毫秒)
);
实验九第一部分最终结果如下图:
第一部分程序如下:
classCtest9//定义一个类
{
public:
Ctest9(){m」=0;};
voidSet(inti){m」=i;};
voidSetId(inti){id=i;};
intGet(){returnm」;};
intGetId(){returnid;};
voidInc(){m」+=1;};
private:
intm_i;//累计值
intid;//线程编号};
UINTtestThread1(LPV0IDpParam){//线程主函数
//接收一个窗口类指针,然后设置窗口标题
HWNDhWnd=(HWND)pParam;//将传入的线程函数参数转换
为窗口句柄
while(!
gl_bclose){//判别gl_bclose是否为TRUE,否则线程继续运行Sleep(IOOO);//1s
gl_i+=100;//延时累加
}_
charstr[81];
wsprintf(str,"全局变量值:
%d",gl_i);
AfxMessageBox(str);//显示gl」值
return0;//返回并退出线程
//或者调用voidAfxEndThread(UINTnExitCode);来退出
}
voidOnThreadCreate()
{
gl_bclose=FALSE;
HWNDhWnd=GetSafeHwnd();
AfxBeginThread(testThread1,hWnd);//创建工作线程
}
3.3第二部分一创建优先级不同的双线程:
331创建双线程:
虽然是创建双线程,但其实两个线程的内部工作方式相同,只是传递的参数
不同,因此只需一个线程函数即可:
UINTtestDoubleThread(LPVOIDpParam);
然后利用3.2.2中提到的AfxBeginThread()来创建线程:
AfxBeginThread(testDoubleThread,pParam1,
THREAD_PRIORITY_ABOVE_NORMAL);
//创建第一个线程,优先级高于默认
AfxBeginThread(testDoubleThread,pParam2,
THREAD_PRIORITY_BELOW_NORMAL);
//创建第二个线程,优先级低于默认
3.3.2终止双线程:
同样可以利用3.2中的全局变量gl_bclose来控制线程的结束。
最终结果如下图:
第二部分程序如下:
UINTtestDoubleThread(LPVOIDpParam){//线程主函数
Ctest9*pCtest9;
pCtest9=(Ctest9*)pParam;
while(!
gl_bclose)
{_
Sleep(500);pCtest9->Inc();
}
charstr[81];
wsprintf(str,"线程%d累计值:
%d",
pCtest9->Getld(),pCtest9->Get());
AfxMessageBox(str);
if(pCtest9!
=NULL){deletepCtest9;}
return0;
}voidCMainFrame:
:
OnDoublethreadCreate()
{
gl_bclose=FALSE;
Ctest9*pCtest9_1;pCtest9_1=newCtest9;pCtest9_1->Setld
(1);
LPVOIDpParam1=(LPVOID)pCtest9_1;
AfxBeginThread(testDoubleThread,pParam1,THREAD_PRIORITY_ABOVE_NORMAL);
//创建第一个线程,优先级高于默认
Ctest9*pCtest9_2;pCtest9_2=newCtest9;pCtest9_2->Setld
(2);
LPVOIDpParam2=(LPVOID)pCtest9_2;
AfxBeginThread(testDoubleThread,pParam2,THREAD_PRIORITY_BELOW_NORMAL);
//创建第二个线程,优先级低于默认
}
3.4第三部分一线程的控制:
3.4.1为工程添加变量:
为3个EditBox分别添加成员变量:
intm_Value1;//计数初始值
intm_Value2;//计数增量
intm_Value3;//计数结果
四个按钮分别用来创建线程,暂停/运行,终止线程,显示最终结果。
按钮的状态可由下面两个函数控制:
CButton:
:
EnableWindow(BOOLbEnable);
//TRUE——可用;FALSE——不可用(变灰)
CButton:
:
SetWindowText(LPCTSTRpszString);
//实现将按钮上的字符改变
添加全局变量:
//线程结束标志
//线程挂起标志
boolpause_flag=FALSE;
boolend_flag=FALSE;
intgl_last=0;//全局变量,存放累加值
最终结果如下图:
图1:
创建线程
图2:
线程挂起
图3:
线程结束并显示结果第三部分程序如下:
boolpause_flag=FALSE;//线程结束标志
boolend_flag=FALSE;//线程挂起标志
intgl_last=0;//全局变量,存放累加值
classCTest9_3
{_
public:
CTest9_3(){m」nitValue=m_Step=0;}
voidlnc(){m」nitValue+=m_Step;}
intGetValue(){returnm」nitValue;}
voidSetValue(intv1,intv2){m」nitValue=v1;m_Step=v2;}protected:
private:
intm」nitValue;
intm_Step;
};//〉程序与线程传递的参数
UINTtestThread3(LPVOIDpParam){
CTest9_3*lpc=(CTest9_3*)pParam;
while(!
end_flag)//线程是否结束?
{
Sleep(50);//线程休眠}
Sleep(1000);
lpc->Inc();//延时累加,1s
}
gl_last=lpc->GetValue();//线程结束,保存累加值
if(lpc!
=NULL){deletelpc;}
return0;
}
voidOnThreadBegin()
{
end_flag=FALSE;
pause_flag=FALSE;
gl_last=0;//初始化
UpdateData(TRUE);//获取输入的初始值以及步长值
CTest9_3*lpc;
lpc=newCTest9_3;lpc->SetValue(m_InitValue,m_Step);
LPVOIDpParam=(LPVOID)lpc;//定义线程操作的数据
CButton*button=(CButton*)GetDlgItem(IDC_THREAD_BEGIN);button->EnableWindow(FALSE);//“启动”按钮失效(变灰)
AfxBeginThread(testThread3,pParam);//启动线程
}
voidOnThreadRunpause()
{
CButton*button=(CButton*)GetDlgItem(IDC_THREAD_RUNPAUSE);
if(!
pause_flag)
{pause_flag=TRUE;
button->SetWindowText("运行");//线程运行时显示“挂起”}else
{
pause_flag=FALSE;
button->SetWindowText("挂起");//线程挂起时显示“运行”}
voidOnThreadEnd()
{
CButton*button=(CButton*)GetDlgItem(IDC_THREAD_BEGIN);
button->EnableWindow(TRUE);//使“启动”按钮恢复作用
}
voidOnValueMove()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
m_LastValue=gl_last;
UpdateData(FALSE);//将累加值传递给EditBox变量并在EditBox中显示
}