




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Windows多线程编程作者:韩飜旭多线程编程之问题提出2一、问题的提出2二、多线程概述2三、Win32 API对多线程编程的支持 3四、Win32 API多线程编程例程4例程 1 MultiTlireadl4例程 2 MultiTliread25例程 3 MultiThreadS6例程 4 MultiTliread49多线程编程之二一MFC中的多线程开发11五、MFC对多线程编程的支持11六、MFC多线程编程实例12例程 5 MultiTliread512例程 6 MultiTliread615多线程编程之三一 程间通讯19七、线程间通讯19例程 7 MultiTliread719多线程编程
2、之四一线程的同步23八、线程的同步23例程 8 MultiThreadS24例程 9 MultiTliread926例程 10 MultiThreadlO29订1: 参考 fl http:/hi been net/space-29U696-do-blog-id-13861.html多线程编程之问题提出下载源代码http:7hi.bccn net/lmkphpQurl=%2Fcode%2Fdoxvncodeasp%3Fid%3D29 73一、问题的提出编写一个耗时的单线程程序:新建一个基于对话框的应用程序SmgleTliread ,在主对话框 IDD SINGLETHREAD DIALOG 添加
3、一个按钮,ID 为 IDC_SLEEP_SIX_SECOND,标题为 “延时6杪",添加按五的响应函数,代码如卜:void CSingleThieadDlg:OnSleepSixSecond()Sleep(6000); 延时 6 秒编译并运行应用程序,单击“延时6秒”按饥,你就会发现在这6秒期间程序就象“死 机” 一样,不在响应览它消息。为了更好地处理这种疑时的操作,我们白必要学习一筋线 程编程。二、多线程概述进程和线程都是操作系统的概念。进程是应用程序的执行实例,每个进程是由私右的虚 拟地址空间、代码、数据和英它族种系统资源组成,进程在运行过程中创建的资源随着进程 的终止而被销毁,
4、所使用的系统资源在进程终止时被释放或关闭。线程是进程内部的一个执行单元。系统创建好进程后,实际上就启动执行了该进程的主 执行线程,主执行线程以函数地址形式,比如说mam或WniMain函数,将程序的心动点提 供给Windows系统。主执行线程终止了,进程也就随Z终止。每一个进程至少冇一个主执行线程,它无需由用户去主动创建,是由系统自动创建的。 用户根据需要在应用程序中创建其它线阳 女个线程并发地运行于同一个进朴冲。一个进桿 中的所有线程都在该进程的虚拟地址空间中,共同使用这些虚拟地址空间、全局变量和系统 资源,所以线程间的通讯非常方便,多线程技术的应用也较为广泛。多线程可以实现并行处理,避免了
5、某项任务长时间占用CPU时间。要说明的一点是, H前人多数的计算机都是单处理器(CPU)的,为了运行所有这些线程,操作系统为毎个独 立纟切丫安排一些CPU时河,操作系统以轮换方式向线程提供时间片,这就给人一种假彖, 好彖这些线程都在同时运行。由此町见,如來两个非常活跃的线程为了抢夺对CPU的控制 权,在线程切换时会消耗很多的CPU资源,反而会降低系统的性能。这一点在多线榨编程 时应该注意。Win32 SDK函数支持进行多线程的程序设计,并提供了操作系统原理中的各种同步、 互斥和临界区等操作。Visual C+6.0 «|>,使用MFC类库也实现了多线程的程序设计,使得 多线程编
6、程更加方便。三、Win32 API对多线程编程的支持Wui32提供了一系列的API函数來完成线程的创建、挂起、恢复、终结以及通信等工 作。下面将选取苴中的一些重要函数进行说明。1、HANDLE CreateTliread(LPSECURITY_ATnUBUTES lpTlireadAttiibutes,DWORD dwStackSize,LPTHREAD START ROUTINE IpStartAddress,LPVOID lpParameter,DWORD dwCreatioiiFlags, LPDWORD lpTlireadld);该函数在苴调用进程的进程空间里创建一个新的线程,并返冋已
7、建线程的句柄,其中以参数 说明如卜:lpThreadAttiibutes:指向 个SECl>ITY_ATTRIBUTES结构的指针,该结构决泄了线程的 安全属性,一般置为NULL:dwStackSize:指定了线程的堆栈深度,一般都设置为0:IpStaitAddress:衣示新线程开始执行时代码所在两数的地址,即线程的起始地址。一般情况 为(IJPTHREAD_START_ROUTINE)ThreadFuiic, ThreadFuiic 是线程函数名;IpParameter:指定了线程执行时传送给线程的32位参数,即线程两数的参数; (hreationFlags:控制线程创建的附加标,忐
8、,町以取两种值。如果该参数为0,线程在被创 建后就会工即开始执彳;如果该参数为CREATE_SUSPENDED、则系统产生线程后,该线程 处丁挂起状态,并不马上执行,直至函数ResumeTlnead被调用: lpThreadld:该参数返回所创建线程的ID: 如果创建成功则返冋线程的旬柄,否则返MNULLo2、DWORD SuspendThiead(HANDLE hTliread);该函数用挂起指定的线程,如果两数执行成功,则线程的执行被终止。3、DWORD ResumeThiead(HANDLE hTliread);该函数用结束线程的挂起状态,执彳线程。4、VOID ExitThread(D
9、WORD dwExitCode);该函数用线程终结自身的执行,主耍在线程的执行两数中被调用。比中参数dwExitCode 用来设置线程的退出码。5、BOOL TeiiniiiateThread(HANDLE hTluead,DWORD dwExitCode);一般情况下,线程运行结束z后,线程函数正常返回,但是应用程序可以调用TeniuiiateTliread强行终止某一线程的执行。各参数含义如2hThread:将被终结的线程的句柄; dwExitCode:用丁指定线程的退出码。使用TenmnateTlireadO终止某个线程的执行是不安全的,町能会引起系统不稳定:虽然 该函数立即终止线程的执
10、行,但并不释放线程所占用的资源。|対此,一般不建议使用该函数.6、BOOL PostThieadKIessage(DWORD ldThiead,UINT Msg,WPARAA1 wParam, LPARANI IParam);该函数将一条消息放入到指定线程的消息队列中,并1L不等到消息被该线程处理时便返冋。 idThread:将接收消息的线程的ID;Msg:拆定用來发送的消息:wParam :同消息仃关的字参数;IParam :同消息有关的长参数:调川该函数时,如果即将接收消息的线程没仃创建消息循环,则该函数执疔火败。四、Win32 API多线程编程例程例程 1 MultiThread 1建龙
11、一个基对话框的匸程MiiltiTlireadl,在対话框IDD_MULTITHREAD 1 DIALOG中加 入两个按钮和-个编辑框,两个按钮的ID分别是IDC_START, IDC_STOP ,标题分别为“心动",“停止",IDC_STOP的属性选»|' Disabled:编辑框的ID为IDC_TIME ,属性选 中 Read-only:在MwltiTlireadlDlg.h文件屮添加线程函数川明:void ThieadFunc();注意,线程两数的声明应在类CMultiTlireadlDlg的外部。在类CMdtiTlireadlDlg内部添加 prot
12、ected 型变最:HANDLE hTliread;DWORD ThreadlD:分别代表线程的句柄和ID。在 Mi.iltiTlireadlDlg.cpp 文件1 "添加全局变 hi ni bRun :volatile BOOL m bRiui;m_bRun代表线程是否正在运行。你要留意到全局变鼠:m bRun是便用volatile修饰符的,volatile修饰符的作用是告诉编译 器无需对该变鼠作任何禹优化,即无需将它放到一个寄存器中,并且该值可被外部改变。对 于多线程引用的全局变鼠来说,volatile是一个非常觅要的修饰符。编写线程函数:void TlueadFuncOCTrn
13、ie time;CStnng strTune;m_bRun=TRUE;while(mbRim)time=CTime:GetCiinentTuneO;strTime=time.Fonnat(”H%M%S");:SetDlgltemrext(AfeGetMainWnd()->m_hWnd,lDC_HA 止,strl ime);Sleep(1000);该线程函数没有参数,也不返回函数值。只耍m_bRun为TRUE,线程一直运行。双击IDC_START按钮,完成该按钮的消息换数:void CMultiTlueadlDlg: :OnStart()/ TODO: Add your cont
14、rol notification handler code here hTliread=CreateThiead(NULL.0,(LPTHREADSTARTROUTINE)TlireadFunc.NULL,0,& TlneadlD);GetDlgItem(IDC_START)->EiiableWindoFALSE); GetDlgItem(IDC_STOP)->EnableWindoTRUE);双击IDC_STOP按钮,完成该按钮的消息两数:void CMultiTliread 1 Dig: :OnStop() TODO: Add your control notifica
15、tion handler code herem_bRun=FALSE;GetDlgItem(IDC_START)->EnableWmdoTRUE);GetDlgItem(IDC_STOP)->EiiableWindow(FALSE):编祥并运行该例程,体会使用Win32 API编写的多线程。例 fi! 2 MiiltiThiead2该线程演示了如何传送一个一个整型的参数到一个线程中,以及如何等待一个线程完成 处理。建立-个茲丁对话框的工程MulhThread2,在对话框IDD_MULTITHREAD2_DIALOG屮加 入一个编辑框和 个按钏,ID分别肚IDC_COUNT, IDC
16、_START ,按钮控件的标题为“丿I 始;在MultiThread2Dlg.h文件屮添加线程函数声明:void ThieadFunc(int integer);注意,线程函数的声明丿"在类CMultiThread2Dlg的外部。在类 CMiiltiThread2Dlg 内部添加 protected 型变 ml:HANDLE hTliread;DWORD IhreadlD;分别代农线程的句柄和ID。打丿 I Class Wizard,为编辑框 IDCCOUNT 添加 int 型变 ht m_iiCountc 任 MiiltiTliread2Dlg.cpp 文件中添加:void Thi
17、eadFunc(int integer)mt 1;fbr(i=O;i<integer;i+)Beep(2OO,5O);Sleep(1000);XX.Ii IDC_START按钮,完成该按钮的消息两数:void CMultiTliread2Dlg: :OnStart()UpdateData(TRUE);nit integei-m_nCount;hTliread=CreateThieadQ<ULL,0,(LPTHREADSTARTROUTINE)TlireadFunc,(VOID*)integer,0,& ThreadID);GetDlgItem(IDC_START)->
18、EnableWmdoFALSE);WaitForSmgleObj ect(hThiead,EFINITE);GetDlgItem(IDC_START)->EiiableWindow(TRUE);顺便说一卜WaitForSingleObject两数,其函数原型为:DWORD WaitForSmgleObject(HANDLE hHandle,DWORD dxvMilliseconds); hHandle为耍监视的对彖(一般为同步对彖,也町以是线程)的句柄: dwMilliseconds为liHandle对象所设置的超时值,单位为亳秒;当在某一线稈中调用该换数时,线程暂时:丨起,系统监视hH
19、andle所指向的对象的状态 如果在挂起的dwMdliseconds毫杪内,线程所等待的对彖变为仃信兮状态,则该函数立即返 回:如果超时时间已经到达(hvMilliseconds亳秒,但hHandle所指向的对彖还没仃变成仃信 号状态,P幻数照样返冋。参数(hvMiUiseconds冇两个見冇特殊意义的值:0和INFINITE, 卄为0,则该函数匸即返【叫;若为INFINITE,则线程一肖.被挂起,苴到liHandle所指向的 对彖变为有信号状态时为止。本例程调用该函数的作用是按F IDC_START按钮后,一直等到线程返回,再恢复 IDC_START按钮正常状态。编译运行该例冠并细心体会。例
20、朴! 3 MiiltiThiead3传送一个结构体给一个线程因数也是町能的,可以通过传送一个后向給构体的扌旨针参数来完 成。先定义一个结构体:type 血 f strnctmt firstArgu.long secondArgu, myType, *pN lyType;创建线程时CreateTlireadCNULLOthreadFuncpMyType,.);在tlireadFuiic函数内部,町以使用“强制转换":mt mt ahie=(pMyType)lpvoid)> firstArgu;long loiigX alue=(pMyType)lpvoid)->second
21、dAigii;例程3 MultiThiead3将演示如何传送一个指向结构体的指针参数。建 H个基 对话框的程 MiiltiTliread3.在对话框 IDD_NfULTITHREAD3_DIALOG 中加 入一个编辑框EDC_MILLISECOND, 一个按钮IDC_START,标题为“开始”,一个进度 条 IDC_PROGRESS1:打开 Class Wizard,为编输框 IDCNIILLISECOND 添加 int 熨变灵 miiMilliSecond.为进度 条 IDC PROGRESS1 添加 CProgressCtil 型变啟 m ctrlProgress:在MultiThread
22、SDlg.h文件中添加一个结构的定义:struct thieadlnfoUINT nMilliSecond;CProgressCtrl* pctilPiogress;;线程函数的声明:UINT ThreadFimc(LP"VOID IpParam);注总,二者应在类CMultiThread3Dlg的外部。在类 CMultiThread3Dlg 内部添加 protected 型变 htHANDLE hTliread;DWORD ThieadID;分别代表线程的句柄和ID。在MiiltiTliread3Dlg.cpp文件中进行如卜操作:怎义公共变 ht thieadlnfo Info:双
23、击按钮IDC_START添加相应消息处理函数:void CMiiltiTliread3Dlg: :OnStart() TODO: Add your conti ol notification handler code hereUpdateData(lRUh);hifb.iiNIil liSecoiid=m_nMilhSecond;9Info. pctr lPiogress=&m_ctrlProgress;hTliread=CreateTlMead(NULL,0, (LPTHREAD_START_ROUTINE)TlireadFunc,& Info,0,& Tliread
24、ID);/GetDlgItem(IDC_START)->EnableWmdo<FALSE);WaitF orSingle O 可 ect(hThread,INFINITE); GetDlgItem(IDC_START)>EnableWmdow(TRUE);/在函数 BOOL CMultiHiread3Dlg: :OnInitDialog011 "添加语句:/ TODO: Add extra uutialization herem_ctrlProgiess.SetRange(0,99);m_nMilliSecond= 10;UpdateData(FALSE);retu
25、rn TRUE; / retiun TRUE unless you set the focus to a contiol 添加线程处理函数:UINT ThreadFuiic(LPVOID IpPaiam)threadinfo* pInfo=(thieadInfb*)lpParani;for(mt i=0;i<100;i-H-)int nTemp=pInfo->iiMiliiSecond;pIiifb->pctrlProgiess->SetPos(i);Sleep(nTemp);return 0;顺便补充一点,如果你在void CMultiTluead3Dlg: OnSt
26、artO函数中添加/ */ift句, 编译运行你就会发现进度条不进行刷新,主线程也停止了反应。什么原因呢?这是因为 WaitForSingleObject两数等待子线程(ThreadFunc )结束时,导致线ft!死锁。因为 WaitForSmgleObject函数会将主线程挂起(任何消息都衍不到处理),而子线程ThreadFunc 正在设置进度条,一直在等待主线程将刷新消息处理完毕返回才会检测通知事件。这样两个 线程都在互相等待,死锁发生了,編程时应注意避免.例 f'i! 4 MultiThiead4该例程测试在Wmdows卜最多可创建线程的数目建、Z个基 对话框的 I程 MiUti
27、TlireacU.在对话框 IDD_MULTITHREAD4_DIALOG 中加 入-个按钮IDC_TEST和-个编辑框IDC_COUNT,按钮标题为“测试”,编辑框属性选 中 Read-only:在MultiThread4Dlg.q>p文件中进行如卜操作:添加公共变量volatile BOOL m_bRuiiFlag=TRUE;该变駅表示是否述能继续创建线程。添加线程函数:DWORD WINAPI threadFimc(LPVOID theadNum)while(mbRunFlag)Sleep(3000);return 0;只耍m_bRiuiFlag变最为TRUE,线程一宜运行。双击按
28、钮IDC_TEST,添加其响应消息函数:void CMxiltiTliread4Dlg: :OnTestODWORD threadID,GetDlgItem(IDC_TEST)->EnableWmdow(FALSE);long nCoxmt=0;while(mbRiinFlag)if(CreateTlireadQ<ULL,O,thieadFunc,NULL,O>&thieadID)=NULL)m_bRtuiFlag=FALSE;break;elsenCouiit+;不断创建线程,苴到再不能创建为止m_nC oiuit=nC ount;UpdateData(FALSE)
29、;Sleep(SOOO);延时5秒,等待所冇创建的线程结束GetDlgItem(IDC_TEST)>EnableWindow(TRUE); m_bRuiiFlag=TRUE.11多线程编程之二一MFC中的多线程开发下载源代码http: hi.bccn net/lmk phpurluhttp:/, www.vckbase com%2Fcode%2Fdoxvncode asp%3Fid%3D29 75五、MFC对多线程编程的支持MFC屮有两类线程,分别称Z为匚作者线程和用户界面线程。二者的主婆区别在匚 作者线程没仃消息循环,而用户界而线程右自C的消息队列和消息循环。工作者线程没仃消息机制,通
30、常用來执行后台计算和维护任务,如冗长的计算过程,打 印机的后台打印等。用户界面线程一般用处理独VJ-K他线程执行Z外的用户输入,响应 川八及系统所产生的事件和消息等。但对J - Win32的API编程血金,这两种线程是没仃区 别的,它们都只需线程的启动地址即町启动线程來执行任务。在MFC中,一般用全局函数AfxBegmThreadO来创建并初始化一个线程的运行,该两 数有两种咆我形式,分别用创建匚作者线程和用户界面线程。两种咆我函数原型利参数分 别说明如下:(1) CWinThiead* AfxBegniThiead(AFX_THREADPROC pfhThreadPioc,LPVOID pP
31、aram,nPiionty=THREAD_PRIORITY_NORMAL,UINT nStackSize=O, DWORD dwCreateFlags=O, LPSECURITY ATTRIBUTES lpSeciintyAttrs=NULL);PfiiThreadPioc:指向工作者线程的执行驢的指针,线程函数原型必须川明如UINT ExecutmgFunctionCLPXID pParam);请注.&,ExecutmgFunction()N返冋一个UINT类空的值,用以指明该两数结朿的原因。一 般情况卜,返回0表明执行成功。pParam:传递给线程函数的 个32位参数,执行函数将用
32、某种方式解释该值。它町以圧圾 值,或是指向一个结构的指针,甚至可以被忽略:nPnonty:线程的优先级。如果为0,则线程与苴父线程貝冇相同的优先级;nStackSize:线程为自己分配堆栈的人小,其单位为字节。如果nStackSize被设为0,则线程 的堆栈被设置成与父线程堆栈相同人小:dwCreateFlags:如果为0,则线程在创建后立刻开始执行。如呆为CREAEE_SUSPEND,则 线程在创建后立刻被挂起;IpSecuntyAttrs:线程的安全属性指针,一般为NULL:(2) CWmTlnead* AfxBegmTliread(CRuiitiiiieClass* pThieadCla
33、ss,mt iiPnonty=THREAD_PRIORITY_NORMAL>UINT nStackSize=O,DWORD dwCreateFlags=O,LPSECURITY ATTRIBUTES lpSeciirityAttrs=NULL);pTlireadClass是指向CWmThiead的一个导出类的运行时类对彖的指针,该导出类定 义了被创建的用户界面线程的启幼、退出等:梵它参数的意义同形式1。使用丙数的这个原 型生成的线程也有消息机制,在以后的例子屮我们将发现同主线程的机制儿乎一样。卜面我们对CWinThread类的数据成城及常用函数进分简要说明。m_hThiead:肖前线榨的
34、句柄: m_nThieadID:当前线程的ID ; m_pMainWnd:指向丿垃用程序上谢I 1的指针 BOOL CWinThiead: :CreateThiead(DWORD dvCreateFlags=O, UINT nStackSize=O,LPSECURITY_ATTRIBUTES lpSeciintyAttrs=NXJLL);该函数中的 dwCreateFlags、nStackSize、IpSecuntyAttrs 参数和 API 函数 CreateThiead 中的对应参数冇相同含义,该函数执行成功,返回非0值,否则返回0。一般情况卜,调用AfkBeginThreadO来一次性地
35、创建并启动一个线程,但是也町以通过 两歩汰來创建线用:许先创建CWmThread类的一个对象,然后调用该对彖的成员函数 CreateThread()來启动该线程。virtual BOOL CWinThread:Imtlnstance();車载?该函数以控制用户界血线程实例的初始化。初始化成功则返回非0值,否则返也1 0; 用户界面线程经常重载该函数,工作者线程-般不使用ImtlnstanceOo virtual int CWmThread: :ExitInstance();在线程终结前贞载该函数进行一些必要的消理匸作。该函数返冋线程的退出码,0 农不执行成功,非0值用來标识各种错谋。同Imtl
36、iistanceO成员两数一样,该因数也只适用 丁用户界而线程。六、MFC多线程编程实例在Visual C+6-0编程环境中,我们既可以编写C风格的32位Win32应用程序,也可 以利用MFC类库编写C卄风格的应用程序,二者兀冇英优缺点。皋Win32的W用程序执 行代码小巧,运行效率局,但耍求程序员编写的代码校多,II需耍管理系统提供给程序的所 仃资源:而基J-MFC类库的应用程序町以快速建立起应用程序,类库为程序员提供了人彊 的封装炎,而fl. Developer Studio为程序员提供了一些工貝來管理用户源程序,其缺点是类 库代码很庞人。tfl使用类库所带来的快速、简捷和功能强人等优越性
37、,I対此除作冇特殊的 需要,否则Visual C卄推荐使用MFC类库进行程序开发。我们知道,MFC中的线程分为两种:用户界面线程和工作者线程。我们将分别举例说明用MFC类库编程实现工作者线程例程 5 MultiThreadS为了与Win32 API对照,我们使用MFC类库编程实现例程3 NhiltiThread3o建立-个阜丁对话框的工程MulhThread5,在对话框IDD_MULTITHREAD5_DIALOG屮加 入一个编辑框IDC NllLLlSbCOND, 一个按钮1DC_S1AR1,标题为“开始”,一个进度 条 IDC PROGRESS 1;13打开 ClassWizard>
38、 为编徘框 IDCMILLISECOND 添加 mt 型变彊 mjiMiUiSecond,为进度 条 IDC_PROGRESS1 添加 CProgiessCtrl 型变駅 m_ctilProgress:在NMtiTliread5Dlg.h文件中添加一个结构的定义:stiuct tlireadlnfoUINT liMilliSecond;CProgressCtrl* pctrlPiogiess;线程函数的声明:UINT ThieadFunc(LP*OID IpParam);注恿,一-者应在类CMultiThi ead5Dlg的外部。右匚类CNItiltiThread5Dlg内部添加protect
39、ed型变;衣:CWinThread* pThiead;在MiiltiTliread5Dlg.cpp文件中进行如卜操作:定义公共变缶tlireadlnfo Info;双击按钮IDC_START添加相应消息处理函数:void CNIultiTliread5Dlg: :OnStart() TODO: Add yotir contiol notification handler code hereUpdateData(TRUE);IiifoiiNIil liSecoiid=m_nMilhSec0nd;Iiifb.pctrlPiogiess=&m_ctrlProgiess;pTliread=Af
40、xBeginTliread(ThieadFunc,&Info);在函数 BOOL CMultiThread3Dlg:OnInitDialogO添加语句:/ TODO: Add exti-a mitialization here m_ctrlProgiess.SetRaiige(0,99);m_nMilliSecond= 10;UpdateData(FALSE);return TRUE; / return TRUE unless you set the focus to a contiol 添加线程处理函数:UINT ThreadFunc(LPOID IpParam)tlireadlnf
41、o* pInfo=(thieadInfo*)lpParam;for(mt i=0;K100;i+)int nTemp=pInfb >nMilliSecoiid;pIiifo->pctrlProgiess->SetPos(i);Sleep(nTemp);return 0;用MFC类库编程实现用户界而线程创建用户界面线程的步骤:使用ClassWizard创建类CWinThiead的派定类(以CUIThiead类为例) class CUIThread public CWinTlireadDECLARE_DYNCREATE(CUITliread)piotected:CUIThread
42、();/ protected constnictor used by dynamic creation/ Attnbutespublic:H Operationspublic:/ Ovemdes/ ClassWizard geneiated virtual fiinction overndes/AFX_IRTUAL(CUIThread)public:virtual BOOL Iiiitlnstance();irtual mt Exitliistaiice();/AFX_MRTUAL/ Implementationpiotected:virtual -CUIThiead();/ Generate
43、d message map functions/AFX_MSG(CUITliread)/NOTE - the ClassWizard will add and remove member fiuictions here.AFX_MSGDECLARE_MESSAGE_MAP();重载函数 Iiutlnstance()和 ExitlnstanceO。BOOL CUITliread: InitlnstanceOCFrameWnd* wnd=new CFrameWnd,wd->Create(NULL/UI Thiead Window”);wnd>ShowWmdow(SW_SHOW);wnd
44、>UpdateW indov();m_pMainW nd=und;return TRUE;创建新的用户界ihi线程void ClJIThieadDIg: :OnButtonl ()CUIThread* pThiead=new CUIThieadO;pTliread-X?reateThiead();请注意以卜两点:A、(W UIThreadDlg.cpp 的)|:头加入i/i <>J:include "UTThread h"B、把UTThread h中类CUIThread()的构造函数的特性由protected改为public«用户界面线程的执行次
45、序与应用程序主线程柑同,首先调用用户界面线程类的 InitlnstanceO数,如果返回TRUE,继续调用线程的Run()函数,该函数的作用是运彳J:一个 标冷的消息循环,并II、勺收到WM_QUIT消息后中断,在消息循坏过程中,RunO函数检测 到线程空闲时(没冇消息),也将调用Onldle()函数,最后Rim()两数返冋,MFC调用 ExitlnstanceO两数清理资源。你叮以创建一个没仃界面而仃消息循环的线程,例如:你可以从CWmThiead派生一个 新类,在Iiutlnstance函数中完成菜项任务并返回FALSE,这衷示仅执行Iiutlnstance函数小 的任务而不执行消息循环,
46、你町以通过这种方法,完成一个工作者线程的功能。例川 6 MiiltiThiead6建亡一个基对话框的丁程MiiltiTliread6在对话框IDD_MULTITHREAD6_DIALOG屮加 入一个按钮IDC_UI_THREAD,标题为“用户界面线程”右Ji匸程并选中"New Class”为工程添加圾类为CWmThiead派生线程类CUITliieado 给工程添加新对话框IDD_UITHREADDLG,标题为“线程对话框"。为对话框 IDD UITHREADDLG 创建一个某 J CDialog 的类 CUIThieadDlgo 使用 ClassWizard 为 CXJI
47、ThreadDlg 类添加 WM_LBUTTONDOWN 消息的处理凶数 OnLButtonDown,如 F: void CUIThieadDlg: :OnLButtonDown(UINT nFlags, CPoint pomt)AfxNlessageBoxC'You Clicked rhe Left Button?");CDialog: :OnLButtonDown(iiFlags, point);在UTHiread li屮添加#include "UIThreadDlg IT并在 CUITliread 类屮添加 protected 变;it CUIThreadlg
48、m_dlg:class CUITliread public CWinTlireadDECLARE_DYNCREATE(CUITliread)piotected:CUIThread();/ protected constiiictor used by dynamic creation/ Attnbutespublic: Operationspublic:/ Ovemdes ClassWizard generated virtual fiuiction overndes/AFXTRTUAL(CUIThread)public:virtual BOOL Imtlnstance();irtual int
49、 ExitliistaiiceO;AFX_TRTUALH Iniplementatioiipiotected:CUIThreadDlg m_dlg;virtual -CUIThread();/ Generated iwessage map fiinctions/AFX_MSG(CUIThread)/ NOTE - the ClassWizard will add and remove member fiuictions here./AFX_MSGDECLARE_MESSAGE>IAP();分别 iR & Iiutlnstance()函数和 ExitliistaiiceO 函数:B
50、OOL ClJIThiead: ImtliistanceOm_dlg.Create(IDD_UITHREADDLG);m_dlg. ShowWindox(SW_SHOW);mjpIainWiid=&m_dlg;return IRUb;17int CUIThiead:ExitlnstanceOm_dlg DestroyWindoO ; return CWmTluead:ExitlnstanceO;代码中mt CUIThiead: ExitlnstanceOin_dlg. Destroy Window。;return CWmTlnead:ExitlnstanceO;不会被执行所以导致内存泄
51、露。对以在 void CUIThieadDlg: :OnOK()/ TODO: Add extra validation hereCDialog:OnOK0;DestroyWindow();void CUIThieadDlg: :OnCancel()/ TODO: Add extra cleanup CDialogCDialog: OiiCancelO;DestroyWindow();增加DestroyWmdoO;来销毁对象;或者在CUITliread中声明的CUIThreadDlg指针來操作: 在 void CUIThreadDlg: :OnDestroy()CDialog: OiiDest
52、royO;delete this; TODO: Add yoiu- message handler code here调用 delete this;总之.耍把Create I J的对彖调用DestroyWindoO 来销毁双击按钮IDC_UI_THREAD添加消息响应函数: void CMultiTliread6Dlg: :OnUiTliread()CWmThread *pThread=AfxBeginThiead(RUNTIME_CLASS(CUmiiead);并在MultiThread6Dlg.cpp的开头添加:#include MUITliread hM好了,编译并运行程序吧。每单击一次
53、“用户界面线程”按钮,都会弹出一个线程对话 框.在任何一个线程对话框内按卜鼠标左键,都会弹出一个消息框。#多线程编程之三线程间通讯下载源代码http: hi.bccn liet/lmk phpurlnhttp:/, %2Fcode%2Fdoxvncode asp%3Fid%3D29 76七、线程间通讯一般Ifti言,应用程序屮的一个次耍线程总是为主线程执行特定的任务,这样,主线程和次 耍红程间必定仃-个信息传递的渠道,也就是主线程和次要线程间耍进彳了通信。这种线程间 的通信不但是难以避免的,而且在多线程编程屮也是复杂和频繁的,卜-而将进行说明。使用全局变量进行通信由丁属J:同一个进程的齐个线程
54、共亨操作系统分配该进程的资源,故解决线程间通信最简单 的一种方法是使用全丿变杲。対标准类型的全局变駅,我们建议使用volatile修饰符,它 告诉编译器无碍对该变磺作任何的优化,即无石将它放到 个寄心器屮,并IL该值可被外部 改变。如來线程间所需传递的信息较复杂,我们町以定义-个结构,通过传递指向该结构的 指针进行传递信息。便用自定义消息我们町以在一个线程的执行畅数中向另一个线程发送自定义的消息来达到通信的冃的。一个 线榨向另外一个线榨发送消息是通过操作系统实现的。利用Wmdows操作系统的消息张动 机制,当一个线用发出一条消息时,操作系统首先接收到该消息,然后把该消息转发给目标 线程,接收消
55、息的线程必须已经建立了消息循环。例 f'r 7 MultiThiead7该例程演示了如何使用门定义消息进行线程间通信。11先,主线程向CCalculateThiead 线料发送消息WM CALCULATE, CCalculateThiead线程收到消息后进行计算,再向主线程 发送WN1_DISPLAY消息,主线程收到该消息后显示计算结果。建立-个茲丁对话框的工程MulhThread7,在对话框IDD_MULTITHREAD7 DIALOG屮加 入三个单选按钮 IDC RADIOl. IDC RADIO2. IDC_RADIO3,标题分别为 1+2+3+4+10. 1+2+3+4+50,
56、 1+2+3+4+100。加入按钮IDC SUM,标题为“求和"。加入标签框 IDC_STATUS,属性选屮“边框": 在MiiltiTliread7Dlg.h屮定义如卜变駅:piotected:mt nAddend:代表加数的人小。分别双击三个单选按钮,添加消总响W函数: void CMultiTliread7Dlg: :OnRadio 1 ()nAddend=10;void CMultiTliread7Dlg: :OnRadio2() iiAddend=50;void CMiiltiTliread7Dlg: :OnRadio30iiAddend= 100;并在OiihutDialog惭数中完成相应的初始化匚作:BOOL CMultiTliread7Dlg: OnImtDialog()(CButton*)GetDlgItem(IDC_RADIO 1 )&
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 护理培训计划课件
- 2025年广东中山高技术产业开发区事业单位招聘考试试题【答案】
- 2025年北海市银海区审计局财务审计人员招聘考试笔试试题【答案】
- 儿童画挂毯课件图片
- 儿童画小锦鲤课件
- 电信业务合作协议之通信网络维护服务合同
- 人文知识美术课件
- 儿童画外太空课件
- 儿童画图案课件
- 服务流程培训课件
- c2考驾照科目一试题及答案
- AFU阿芙精油品牌手册
- 2025内蒙古包头农商行社会招聘10人笔试历年典型考题及考点剖析附带答案详解
- 2025年中国军工用电源模块项目投资可行性研究报告
- 2025明光事业单位笔试真题
- 2025房县事业单位笔试真题
- DBJ50T-195-2025 混凝土抗压强度检测技术标准
- 《南昌市海绵城市建设规划设计导则》
- 牙齿漂白治疗技术操作指南
- 道路施工工艺培训
- 2025-2030全球及中国乙酰柠檬酸三丁酯(ATBC)行业市场现状供需分析及市场深度研究发展前景及规划可行性分析研究报告
评论
0/150
提交评论