ImageVerifierCode 换一换
格式:DOCX , 页数:16 ,大小:20.91KB ,
资源ID:3222810      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-3222810.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(线程函数的设计以及MsgWaitForMultipleObjects函数的使用要点文档格式.docx)为本站会员(b****2)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

线程函数的设计以及MsgWaitForMultipleObjects函数的使用要点文档格式.docx

1、return 0;/类的成员函数,此函数执行实际的线程函数操作,却可以自如的调用成员数据void CThreadTest:SetProgress()int nCount=0;while (1)m_progress.SetPos(nCount); /设置进度条进度/this-SendMessage(WM_SETPROGRESSPOS,nCount,0);/也可用这种方式nCount+;if (g_exitThread)return;Sleep(200);二线程函数体的设计有过多线程设计经验的人都有体会,多线程设计最重要的就是要处理好线程间的同步和通讯问题。如解决不好这个问题,会给程序带来潜藏的隐

2、患。线程的同步可以利用临界区、事件、互斥体和信号量来实现,线程间的通讯可利用全局变量和发消息的形式实现。其中事件和临界区是使用得比较多的工具。请看下面的线程函数体:UINT AnalyseProc(LPVOIDlVOID)if(WAIT_OBJECT_0= WaitForSingleObject(m_eventStartAnalyse.m_hThread,INFINITE)while (WAIT_OBJECT_0 = WaitForSingleObject(m_eventExitAnalyse.m_hThread,0)DWORD dRet=WaitForSingleObject(m_event

3、Pause.m_hThread,0);if (dRet = WAIT_OBJECT_0)/暂停分析Sleep(10);else if (dRet = WAIT_TIMEOUT)/继续分析/上面的线程函数用到了三个事件变量eventStartAnalyse、eventExitAnalyse和eventPause,分别用来控制线程函数的启动、退出以及暂停。再配以WaitForSingleObject函数,就可以自如的控制线程函数的执行,这是在线程函数体内应用事件变量的典型方式,也是推荐的方式。无论是工作线程还是用户界面线程,都有消息队列,都可以接收别的线程发过来的消息也可以给别的线程发送消息。给工

4、作线程发消息使用的函数是PostThreadMessage()。此函数的第一个参数是接收消息的线程的ID。此函数是异步执行的,机制和PostMessage一样,就是把消息抛出后就立即返回,不理会消息是否被处理完了。这里还有着重强调一点,线程消息队列是操作系统帮我们维护的一种资源,所以它的容量也是有限制的。笔者曾经做过实验,在56秒事件内调用PostThreadMessage往线程消息队列里发送5万多条消息,可是由于线程函数处理消息的速度远慢于发送速度,结果导致线程消息队列里已经堆满了消息,而发送端还在发消息,最终导致消息队列溢出,很多消息都丢失了。所以,如果你要在短时间内往线程消息队列里发送很

5、多条消息,那就要判断一下PostThreadMessage函数的返回值。当消息队列已经溢出时,此函数返回一个错误值。根据返回值,你就可以控制是否继续发送。工作线程给主线程发消息使用的是SendMessage和PoseMessage函数。这两个函数的区别在于SendMessage函数是阻塞方式,而PoseMessage函数是非阻塞方式。如果不是严格要求工作线程与主线程必须同步执行,则推荐使用PoseMessage。不要在线程函数体内操作MFC控件,因为每个线程都有自己的线程模块状态映射表,在一个线程中操作另一个线程中创建的MFC对象,会带来意想不到的问题。更不要在线程函数里,直接调用Updata

6、Data()函数更新用户界面,这会导致程序直接crash。而应该通过发送消息给主线程的方式,在主线程的消息响应函数里操作控件。上面提到的SetProgress函数和AnalyseProc函数均为线程函数,但它们都不能接收别的线程发过来的消息,虽然它们都可以给主线程发消息。它们要想能够接收别的线程发过来的消息,则必须调用GetMessage或PeekMessage函数。这两个函数的主要区别在于:GetMessage函数可以从消息队列中抓取消息,当抓取到消息后,GetMessage函数会将此条消息从消息队列中删除。而且,如果消息队列中没有消息,则GetMessage函数不会返回,CPU转而回去执行

7、别的线程,释放控制权。GetMessage返回的条件是抓取的消息是WM_QUIT。PeekMessage函数也可以从消息队列中抓取消息,如果它的最后一个参数设置为PM_NOREMOVE,则不从消息队列中删除此条消息,此条消息会一直保留在消息队列中。如果它的最后一个参数是PM_REMOVE,则会删除此条消息。如果消息队列中没有消息,则PeekMessage函数会立刻返回,而不是像GetMessage一样就那样等在那儿。PeekMessage函数就像是窥探一下消息队列,看看有没有消息,有的话就处理,没有就离开了。这一点也是两个函数的最大不同。下面的代码演示了在线程函数中使用这两个函数的三种方式,这

8、三种方法可以达到同样的效果:SetSlider()/在线程函数里启动一个时钟,每50毫秒发送一个WM_TIMER消息int nTimerID=:SetTimer(NULL,1,50,NULL);int nSliderPos=0;MSG msg;/方式一使用GetMessage函数/*if (:GetMessage(&msg,NULL,0,0)switch(msg.message)case WM_TIMER:nSliderPos+;SendMessage(this-m_hWnd,WM_SETSLIDERPOS,nSliderPos,0);break;case WM_QUIT_THREAD:/自定

9、义消息KillTimer(NULL,1);default:*/方式二使用PeekMessage函数PeekMessage(&msg,NULL,0,0,PM_REMOVE) /自定义消息else/必须有此操作,要不然当没有消息到来时,线程函数相当于陷/入空循环,cpu的占有率会飙升Sleep(20);/方式三同时使用PeekMessage和GetMessage函数msg,NULL,0,0,PM_NOREMOVE)if(:前面已经介绍过了,不建议线程函数里用SendMessage给主线程发消息,因为这个函数是同步操作,就是如果SendMessage函数不执行完,是不会返回的,这样线程函数就无法继续

10、执行。有时这种操作容易导致工作线程和主线程死锁,这个我们后面会谈到,会介绍一种解决方法。三线程的退出线程的退出有多种方式,比如可以调用TerminateThread()函数强制线程退出,但不推荐这种方式,因为这样做会导致线程中的资源来不及释放。最好的也是推荐的方式,是让线程函数自己退出。就像上面介绍的SetProgress()函数中,用全局变量g_exitThread使线程退出。而AnalyseProc用WAIT_OBJECT_0=WaitForSingleObject(m_eventExitAnalyse.m_hThread,0)这种方式来退出线程,还有在SetSlider函数中利用发送自定

11、义消息WM_QUIT_THREAD的方式令线程退出。这些都是可以使用的方法。当主线程要退出时,为了能保证线程的资源能全部地释放,主线程必须等待工作线程退出。线程对象和进程对象一样,也是内核对象,而且线程对象的特点是当线程退出时,线程内核对象会自动变为有信号状态,能够唤醒所有正在等待它的线程。我们通常都习惯于使用WaitForSingleObject等函数来等待某个内核对象变为有信号状态,但是我想说的是,在主线程中不要使用WaitForSingleObject和WaitForMultipleObjects两个函数等待线程退出,其原因就是有导致程序死锁的隐患,特别是线程函数里调用了SendMess

12、age或是直接操作了MFC对象,更易出现此种现象。下面的函数是一个在主线程中用来等待SetProgress()线程函数退出的函数:/退出线程OnButton2()g_exitThread=TRUE;/设置全局变量为真,令线程退出#if 1WaitForSingleObject(m_pThread1-m_hThread,INFINITE); /无限等待#elseDWORD dRet;dRet=:MsgWaitForMultipleObjects(1,&m_pThread1-m_hThread,FALSE,INFINITE,QS_ALLINPUT);if (dRet = WAIT_OBJECT_0

13、+1)while (PeekMessage(&TranslateMessage(&msg);DispatchMessage(&#endif在上面的函数中我用#if#else#endif这组预编译指令控制函数的执行代码,如果我令#if 1,则执行WaitForSingleObject函数,如果我令#if 0,则执行DWORD dRet路径。首先令#if 1,测试会发现,程序死锁了。原因是当程序执行到WaitForSingleObject函数时,主线程挂起,等待线程函数退出,此时CPU切换到线程函数体内执行,如果执行到if (g_exitThread)处,则线程函数顺利退出,可如果执行到m_pro

14、gress.SetPos(nCount)处,由于SetPos函数是在主线程中完成的操作,Windows是基于消息的操作系统,很多操作都是靠发消息完成的,由于主线程已经挂起,所以没有机会去消息队列中抓取消息并处理它,结果导致SetPos函数不会返回,工作线程也被挂起,典型的死锁。如果不用m_progress.SetPos,而改用this-SendMessage(),其结果是一样的。此时如果用了PostMessage,则工作线程会顺利退出,因为PostMessage是异步执行的。由此可见,在主线程中用WaitForSingleObject等待工作线程退出是有很大隐患的。为解决这一问题,微软特提供了

15、一个MsgWaitForMultipleObjects函数,该函数的特点是它不但可以等待内核对象,还可以等消息。也就是当有消息到来时,该函数也一样可以返回,并处理消息,这样就给了工作线程退出的机会。DWORD MsgWaitForMultipleObjects(DWORD nCount, /要等待的内核对象数目LPHANDLE pHandles, /要等待的内核对象句柄数组指针BOOL fWaitAll, /是等待全部对象还是单个对象DWORD dwMilliseconds,/等待时间 DWORD dwWakeMask );/等待的消息类型下面就详解一下该函数的参数使用方法:DWORD nCo

16、unt:要等待的内核对象的数目。如果等待两个线程退出,则nCount=2;LPHANDLE pHandles:要等待的内核对象句柄数组指针。如果只要等待一个线程退出,则直接设置该线程句柄的指针即可:m_pThread-m_hThread,)如果要等待两个线程退出,则使用方法为:HANDLE hArray2= m_pThread1-m_hThread , m_pThread2-m_hThread ;MsgWaitForMultipleObjects(2,hArray,)BOOL fWaitAll: TRUE-表示只有要等待的线程全部退出后,此函数才返回,FALSE-表示要等待的线程中任意一个退出

17、了,或是有消息到达了,此函数均会返回。在上面的OnButton2()函数中,我要等待一个线程退出,将fWaitAll设置为FALSE,目的是无论是线程真的退出了,还是有消息到达了,该函数都能返回。如果将该fWaitAll设置为TRUE,那么函数返回的唯一条件是线程退出了,即便是有消息到来了,该函数也一样不会返回。DWORD dwMilliseconds:等待的事件,单位是毫秒。可以设置为INFINITE,无穷等待DWORD dwWakeMask:等待的消息类型,通常可以设置为QS_ALLINPUT。此宏表示的是可以等待任意类型的消息。当然,也可以指定等待的消息类型。#define QS_ALLINPUT (QS_INPUT | QS_POSTMESSAGE QS_TIMER QS_PAINT QS_HOTKEY QS_SENDMESSAGE)返回值:DWORD dRet通过函数返回值,可以得到一些有效信息。函数返回值依fWaitAll设置的不同而有所不同。下面是函数返回值的几种常见类型:dRet =0xFFFFFF

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2