MFC下的多线程编程

上传人:平*** 文档编号:46197598 上传时间:2018-06-23 格式:PPT 页数:30 大小:1.20MB
返回 下载 相关 举报
MFC下的多线程编程_第1页
第1页 / 共30页
MFC下的多线程编程_第2页
第2页 / 共30页
MFC下的多线程编程_第3页
第3页 / 共30页
MFC下的多线程编程_第4页
第4页 / 共30页
MFC下的多线程编程_第5页
第5页 / 共30页
点击查看更多>>
资源描述

《MFC下的多线程编程》由会员分享,可在线阅读,更多相关《MFC下的多线程编程(30页珍藏版)》请在金锄头文库上搜索。

1、LOGOMFC下的多线程编程作者:陈帅2008年7月30日一、MFC 支持的两种线程 : 1. 用户界面线程通常用于处理用户输入及响应用户生成的事件和消 息,并独立地相应正在应用程序其他部分执行的线程产生 的消息和时间,并包含一个消息泵(a Message Pump)。用 户界面线程包含一个消息处理的循环,以应对各种事件 。v 对于用户来说工作线程运行在后台。这就使得工作线程特别 适合去等待一个事件的发生。2. 工作线程v工作线程适用于处理那些不要求用户输入并且比较消耗时 间的其 他任务(如大规模的重复计算,网络数据的发送 与接受)。注意:在MFC应用程序中,所有的线程都是由CWinThrea

2、d对象来表示的;CWinThread是用户接口线程的基类,CWinApp就是CWinThread派生出来 的,在编写用户接口线程时,也需要从CWinThread 类派生出自己的线程类;CWinThread同样是工作线程的基类,但在编写工作线程的时候,升值不 必刻意地从CWinThread类派生出自己的线程类对象。用户可以调用MFC框架 的AfxBeginThread帮助函数,会创建CWinThread对象。在Win32API中不区分两种线程,它只需要知道线程的起始地址,就可以 开始执行线程。3.创建MFC的工作线程(1).编程实现控制函数一个工作线程对应一个控制函数。线程执行的任务都应编写在控

3、制函 数之中。编写实现工作线程的控制函数是创建工作线程的第一步。控制函数的原型声明是:UNIT ControlFunctionName(LPVOID pParam);其中,UNIT ControlFunctionName:是控制函数的名字,自定。 参数pParam:是一个32位指针值,是启动工作线程时,有调用的 AfxBeginThread()函数传递给工作线程的控制函数的。这个值既可以是指 向简单数据类型的指针,用来传递int之类的数值,也可是是指向包含了 许多参数的结构体或其他对象的指针;甚至可以忽略它。(2).创建并启动工作线程在进程的主线程或其他线程中调用AfxBeginThread(

4、)函数就可以创建新 的线程,并使线程开始运行。AfxBeginThread()函数是MFC提供的帮助函数,有两个重载版本,区别 在于使用的入口参数不同。一个用于创建并启动用户接口线程,一个 用于创建并启动工作线程。要创建并启动工作线程,必须采用如下的调用格式:CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_AT

5、TRIBUTES lpSecurityAttrs = NULL ); 参数pfnThreadProc:是一个指向工作线程的控制函数的指针,即控制 函数的地址。创建工作线程是必须指定将在此线程内部运行的控制函 数。参数pParam:是一个指向某种类型的数据结构指针,执行本函数时,将 把这个指针进一步传递给此线程的控制函数,使之成为线程控制函数的 入口参数。参数nPriority:通常设为0。参数nStackSize:通常设为0。参数dwCreateFlags :通常设为0。参数dwCreateFlags :通常设为0。参数lpSecurityAttrs:通常设为NULL。(3)创建工作线程的例子

6、struct int n;double* pD; myData;myData ss;/定义了该类型的变量,对该变量的初始化的代码省略了UNIT MyCalcFunc(LPVOID pParam) /如果入口函数为空指针,终止线程if( pParam=NULL) AfxEndThread(MY_NULL_POINTTER_ERROR);int n=pParam-n; /数组元素个数;double* pD=pParam-pD; /指向数组的第一个元素;double sum=0; /数组元素之和;for(int i=0; in; i+) sum+=pDi;/数组之和;CString bb;bb.Fo

7、rmat(“数组的和是:%d“,sum);/格式化显示字符串;AfxMessageBox(bb); /显示结果;return 0; (i) 编程实现线程控制函数(2)在程序进程的主线程中调用AfxBeginThread()函数来创建并启动运行 这个线程。将控制函数名和结构变量的地址作为参数来传递,其他的参 数省略,表示使用默认值。AfxBeginThread(MyCalcFunc,一旦调用了此函数,线程就被创建,并开始执行线程函数。当 数据的计算完成时,函数将停止运行,线程拥有的堆栈和其它的 资源都将释放。CWinThread对象将被删除。3. 创建并启动用户界面线程创建并启动用户界面线程一般

8、要经过3个步骤:第一步是从CWinThread类派生出自己的线程类;第二步是改造这个线程类,使它能够完成用户所希望的工 作;第三步是创建并启动用户界面线程。(1)从CWinThread类派生出自己的线程类要创建一个MFC的用户界面线程,所要做的第一件事就是从CWinThread 类派生出自己的线程类,一般借助ClassWizard来做这项工作。(2)改造自己的线程类(i)在这个线程类的.h头文件中,使用DECLARE_DYNCRATE宏来声明这个类 ;在用户线程类的.cpp实现文件中,使用IMPLEMENT_DYNCREATE宏来实 现这个类。前者的调用格式是: DECLARE_DYNCRAT

9、E(class_name),其中class_name 中是实际的类名。(ii)如果在一个类中宣布使用了DECLARE_DYNCRATE宏,那么就必须在 这个类的.cpp实现文件中,使用IMPLEMENT_DYNCREATE宏。它的调用 格式是:IMPLEMENT_DYNCREATE(class_name, base_class_name)参数是实际的线程类名和它的基类名。(iii)这个线程类必须重载它的基类(CWinThread类)的某些成员函数,如该类的 InitInstance()成员函数;对于基类的其它成员函数,可以有选择的重载,也 可以使用缺省函数。成员函数名说明ExitInstanc

10、e每当线程终止时,会调用这个函数,执行清理工作,通常需要重 载这个成员函数InitInstance执行线程类实例的初始化,必须重载OnIdle执行线程特定空闲时间处理,一般不重载PreTranslateMessage可以在消息派遣前重新解释消息,过滤消息,将它们分为 TranslateMessage 和DispatchMessage,一般不重载 Run是吃线程的控制函数,为用户的新线程提供了一个消息循环处理 ,包含消息泵,极少重载,但如果需要,也可以重载创建用户界面线程时相关成员函数的重载(vi) 创建新的用户界面窗口类,如窗口、对话框,并添加所需要的用户界 面控件,然后建立新建的线程类与这些

11、用户界面窗口类的联系。(v)利用类向导,为新建的线程类添加控件成员变量,添加响应消息的成员 函数,为它们编写实现的代码经过以上步骤的改造,用户的线程类已经具备了完成用户任务的能力.(3)创建并启用用户界面线程要创建并启动用户界面线程,可以使用MFC提供的AfxBeginThread()函数的另一 个版本,其格式是:CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL,UINT nStackSize = 0, DWORD dwCreateFlags = 0,

12、LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );参数pThreadClass:是一个指向CRuntimeClass类对象的指针,该类是从 CWinThread类继承的。用户界面线程运行时类就在第一步骤从 CWinThread派生的线程类,本参数就指向它,在实际调用时,一般使 用RUNTIME_CLASS 宏将线程类指针转化为指向CRuntimeClass对象的 指针。其他的参数这和创建启动工作线程时一样。4.终止线程(1) 正常终止线程VOID PostQuitMessage()函数的调用格式是:VOID PostQuitMessage(int n

13、ExitCode);参数nExitCode是一个整数型值,指定一个应用程序的终止代码。PostQuitMessage()函数发送一个WM_QUIT消息到线程的消息队列,并 立即返回,没有返回值。函数只是简单地告诉系统,这个线程要求终 止。当线程从它的消息队列收到一个WM_QUIT消息时,会退出它的 消息循环,并将控制权返回给系统,同时把WM_QUIT消息的wParam 参数中的终止代码也返回给系统,线程也就终止了。(2)提前终止线程要想在线程尚未完成它的工作时提前终止线程,只需从线程内 调用AfxEndThread函数,就可以强迫线程终止。此函数的调用 格式是:Void AfxEndThrea

14、d(UNIT nExitCode);参数nExitCode指定了线程的终止代码。执行此函数将停止函数所在线程的执行,撤销该线程的堆栈,解除所有 绑定到此线程动态链接库DLLs,并从内存中删除此线程。(3)终止线程另一种方法:使用Win32 API 提供的TerminateThread()函数,也可以用来终止一 个正在运行的线程,但是它产生的后果是不可预料的,一般仅用来终 止堆栈中的死线程,而且此函数本身不做任何内存的清除工作。5.MFC下多线程的同步机制(1)基本概念:在程序中使用多线程时,一般很少有多个线程能在其生命期内进行 完全独立的操作。更多的情况是一些线程进行某些处理操作,而其他的 线

15、程必须对其处理结果进行了解。正常情况下对这种处理结果的了解应 当在其处理任务完成后进行。下述对象是用来支持同步的:1)信号量2)互斥锁3)临界区4)事件1)信号量 为了限制使用共享资源的线程数目,我们应该使用信号量。信号量是一个内 核对象。它存储了一个计数器变量来跟踪使用共享资源的线程数目。例如,下面 代码使用CSemaphore类创建了一个信号量对象,它确保在给定的时间间隔内(由 构造函数第一个参数指定)最多只有5个线程能使用共享资源。还假定初始时没 有线程获得资源: CSemaphore g_Sem(5, 5); 一旦线程访问共享资源,信号量的计数器就减1.若变为0,则接下来对资源的 访问

16、会被拒绝,直到有一个持有资源的线程离开(也就是说释放了信号量) 。我们可以如下使用: / Try to use the shared resource:WaitForSingleObject(g_Sem, INFINITE);/ Now the users counter of the semaphore has decrementedby one/ Use the shared resource / After we done, let other threads use the resource:ReleaseSemaphore(g_Sem, 1, NULL);/ Now the users counter of the semaphore has incremented by one 互斥锁设计为对同步访问共享资源进行保护。互斥锁在内核中实现, 因此需要进入内核模式操纵它们。互斥锁不仅能在不同线程之间,也可以 在不同进程之间

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号