版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第 10 章 多线程编程,Visual C+程序设计与应用教程,10.1 概述 10.2 线程的创建 10.3 线程的控制 10.4 线程间的通信 10.5 线程间的同步,2,10.1 概述,第10章 多线程编程,大多数操作系统,可以同时运行几个程序,操作系统的这种能力称之为多任务处理。 Windows操作系统用多进程/线程机制提供对一个应用程序内多任务的支持,进程与线程之间是密不可分的,线程依附于进程,一个进程可包含多个线程。,3,10.1.1 问题的提出,【例10.1】创建一个基于对话框的应用程序Li10_1,其界面如图下图所示。按下“开始打印”按钮后,模拟启动一个耗时的打印程序。,第10
2、章 多线程编程,4,10.1.2 进程和线程,进程是应用程序的执行实例,是操作系统分配资源单位。 每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成,进程在运行过程中创建的资源随着进程的终止而被销毁,所使用的系统资源在进程终止时被释放或关闭。 线程是操作系统分配处理器的最基本单元,它是进程内部的一个独立的执行单元。,第10章 多线程编程,5,可以用VC+所带的工具Spy+来观察操作系统管理的进程和线程。 打开Word应用程序和Windows附件中的“记事本”,这样系统内部就产生了两个进程。 选择【Tools|Spy+】菜单命令,打开如下图所示的Spy+应用程序窗口。,第10章 多
3、线程编程,6,第10章 多线程编程,7,第10章 多线程编程,选择【Spy | Processes】菜单命令,在打开的窗口中可以看到操作系统管理的所有进程的信息,如下图所示。,8,10.1.3 MFC对多线程编程的支持,多线程的操作由MFC类CWinThread及其派生类支持,该类的对象代表进程中执行的线程。 下图给出了MFC应用程序框架结构类的继承关系。,第10章 多线程编程,9,从上图可以看出,MFC应用程序类CWinApp是由CWinThread类派生而来的,用于启动进程的主线程。 另外,MFC还提供了支持多线程同步的同步类,如CEvent、CCriticalSection、CSemap
4、hore和 CMutex等。也提供了线程同步辅助类CSingleLock和CMutiLock。,第10章 多线程编程,10,10.2 线程的创建,第10章 多线程编程,MFC中有两类线程,分别称之为工作者线程和用户界面线程。 两者的主要区别在于:工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环。,11,10.2.1 创建工作者线程,创建一个工作者线程,首先需要编写一个希望与应用程序的其余部分并行运行的自定义函数,该函数称为线程函数。然后,在程序中合适的地方调用全局函数AfxBeginThread()创建线程,启动线程函数。,第10章 多线程编程,12,1.定义线程函数 线程函数
5、的固定形式: UINT FunctionName (LPVOID pParam) FunctionName是用户自定义的函数名,LPVOID表示指向空类型的指针,相当于void*,必要时需要把这个指针转换成所需要的类型。函数的返回值将作为线程的结束码,线程函数结束后线程就自动终止。函数的返回值如果为0,表示线程函数正常结束。,第10章 多线程编程,13,2启动线程函数 CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority=THREAD_PRIORITY_NORMAL, UIN
6、T nStackSize=0, DWORD dwCreateFlags=0, LPSECURITY_ATTRIBUTES lpSecurityAttrs= NULL); pfnThreadProc是一个指向线程函数的指针,参数pParam的类型与线程函数的参数类型完全一致,该参数为启动线程时传递给线程函数的入口参数。其他几个参数用于设置线程优先级、线程的堆栈大小、创建时是否立即运行及线程的安全属性,这4个参数通常使用默认值。,第10章 多线程编程,14,【例10.2】编写一个创建工作线程的单文档应用程序Li10_2,当执行【计算素数】菜单命令时启动一个工作线程,计算11000000之间素数的个
7、数。,第10章 多线程编程,15,第10章 多线程编程,10.2.2 创建用户界面线程 用户界面线程通常用来处理用户输入并响应各种事件和消息,它是通过自己的消息泵获取从系统接收到的消息。MFC将为该线程增加一个消息循环,以便能够处理收到的消息。 创建用户界面线程的过程与创建一个工作者线程的过程完全不同。一个工作者线程用由一个线程函数代表,但一个用户界面线程的行为由CWinThread类的派生类来控制。,16,第10章 多线程编程,创建用户界面线程的AfxBeginThread()函数: CWinThread* AfxBeginThread( CRuntimeClass* pThreadClas
8、s, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags=0, LPSECURITY_ATTRIBUTES pSecurityAttrs = NULL ); pThreadClass指向一个CRuntimeClass对象,该对象是用RUNTIME_CLASS宏从CWinThread的派生类创建的。其他参数的含义与前述的函数AfxBeginThread()一样。,17,第10章 多线程编程,在程序中创建一个用户界面线程: AfxBeginThread (RUNTIME_CLASS (cl
9、ass_name); 实参class_name是CWinThread的派生类的名字。,18,第10章 多线程编程,【例10.3】 在基于对话框的应用程序Li10_3中创建用户界面线程。每单击一次“用户界面线程”按钮,都会弹出一个线程对话框,在任何一个线程对话框内按下鼠标左键,都会弹出一个消息框,效果如下图所示。,19,10.3 线程的控制,第10章 多线程编程,线程控制是指控制线程的状态。 从以下几个方面控制线程: 创建一个线程、终止一个线程、挂起一个正运行的线程、激活一个暂停运行的线程、读取和设置线程的优先级、使当前线程等待一定的时间及放弃一个或多个运行时间片等。,20,10.3.1 终止一
10、个线程,第10章 多线程编程,当一个工作者线程的线程函数执行一个返回语句或者调用AfxEndThread( )成员函数时,这个工作者线程就终止。 AfxEndThread()函数原型: void AfxEndThread(UNIT nExitCode); 参数nExitCode表示线程的32位退出码。,21,10.3.2 悬挂和恢复线程,第10章 多线程编程,CWinThread类中包含线程悬挂和恢复的成员函数。 悬挂就是挂起或暂定线程的运行。悬挂函数: DWORD CWinThread:SuspendThread(); 恢复就是激活一个暂停运行的线程,即被悬挂的线程。恢复函数: DWORD
11、CWinThread:ResumeThread();,22,10.3.3 线程的优先级,第10章 多线程编程,使用CWinThread:SetThreadPriority函数设置线程的相对优先级: 使用CWinThread:GetThreadPriority函数获取线程的相对优先级: int GetThreadPriority(HANDLE hThread); 参数hThread是要设置或获取优先级线程的句柄,参数nPriority就是要设置的优先级。,BOOL SetThreadPriority(HANDLE hThread,int nPriority);,23,第10章 多线程编程,【例1
12、0.4】在基于对话框的应用程序Li10_4中,首先创建两个工作线程,分别控制滑动条及进度条的走动,然后对线程进行控制,包括挂起、唤醒、停止及优先级的设置。程序运行界面如下图所示。,24,第10章 多线程编程,10.4 线程间的通信,一般可以使用全局变量进行通信和自定义消息进行通信。 10.4.1 使用全局变量进行通信 对于标准类型的全局变量,建议使用volatile 修饰符,它告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值可被外部改变。如果线程间所需传递的信息较复杂,可以定义一个结构,通过传递指向该结构的指针进行传递信息。接着让线程监视这个变量,当这个变量符合一定的条
13、件时,表示线程应该终止。,25,第10章 多线程编程,10.4.2 使用自定义消息进行通信 使用Windows消息来进行通讯,首先需要定义一个自定义消息,然后,需要时在一个线程中调用全局函数:PostMessage()向另一个线程发送自定义消息。PostMessage()函数的原型为: BOOL PostMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam); hwnd为发送窗口的句柄,Msg为消息的ID,wParam和lParam为消息的相关参数。,26,第10章 多线程编程,【例10.5】完善例10.2中的 Li10_2,Cal
14、culateprime()线程函数执行完后,向主线程发送消息,主线程收到该消息后再显示计算结果。,27,第10章 多线程编程,使隶属于同一进程的各线程协调一致地工作称为线程的同步。 在多线程的环境里,需要对线程进行同步。常用的同步对象有临界区、互斥、信号量和事件。,10.5 线程间的同步,28,第10章 多线程编程,当多个线程访问临界区时,可以使用临界区对象,即CCriticalSection类的对象。临界区是一个独占性共享资源,任一时刻只有一个线程可以拥有临界区。,10.5.1 使用CCriticalSection类,29,第10章 多线程编程,CCriticalSection类的用法有两种
15、: 方法一:单独使用CCriticalSection对象 步骤如下: (1) 定义CCriticalSection类的一个全局对象(以使各个线程均能访问),如: CCriticalSection critical_section; CCriticalSection类的构造函数只有一种形式,即不带任何参数,如上述代码所示。,30,第10章 多线程编程,(2)在访问临界区之前,调用CCriticalSection类的成员Lock()获得临界区。 critical_section.Lock(); 其中Lock()的原型: BOOL Lock(); 在线程中调用该函数来使线程获得它所请求的临界区。如果
16、此时没有其他线程占有临界区,则调用Lock()的线程获得临界区;否则,线程即将挂起,并放入到一个系统队列中等待,直到当前拥有临界区的线程释放了临界区时为止。,31,第10章 多线程编程,(3) 在本线程中访问临界区中的共享资源。 (4)访问临界区完毕后,使用CCriticalSection的成员函数UnLock()来释放临界区。 critical_section.UnLock();,32,第10章 多线程编程,方法二:与同步辅助类CSingleLock或CMutiLock类一起使用,步骤如下(以类CSingleLock为例): (1)定义CCriticalSection类的一个全局对象crit
17、ical_section: CCriticalSection critical_section; (2)在访问临界区之前,定义CSingleLock类的一个对象,并将critical_section的地址传送给构造函数,如: CSingleLock singlelock( 其中,CSingleLock类的成员函数Lock()原型: BOOL Lock(DWORD dwTimeOut=INFINITE); 该函数替它所在的线程申请获得临界区。如果临界区已经被其他线程占用,则本线程挂起,等待临界区被释放。获得临界区(返回TRUE)或等待时间超过dwTimeOut()毫秒(返回FALSE)后均返回。
18、,34,第10章 多线程编程,(4) 在本线程中访问临界区中的共享资源。 (5)调用CSingleLock类的成员函数UnLock()来释放临界区。 singlelock.UnLock();,35,第10章 多线程编程,【例10.6】建立一个基于对话框的应用程序Li10_6,该应用程序中包含两个线程。一个线程向数组中写“A”, 另一个线程向数组中写“B”,使用CCriticalSection类保证在同一时刻只有一个线程能访问共享对象数组。程序运行时,出现如下图所示应用程序界面。,36,第10章 多线程编程,互斥对象与临界区对象相似。互斥对象源于“mutual exclusion”的组合。 临界
19、区对象与互斥对象的不同在于:互斥对象可以在进程间使用,而临界区对象只能在同一进程的各线程间使用。 CMutex类的使用类似于CCriticalSection的用法,下面使用类似于CCriticalSection用法中的第二种用法进行演示说明。,10.5.2 使用CMutex类,37,第10章 多线程编程,【例10.7】修改例10.6中的应用程序Li10_6,使用CMutex类保证在同一时刻只有一个线程能访问共享数据。,38,第10章 多线程编程,10.5.3 使用CSemaphore类,当需要一个计数器来限制可以使用某个资源的线程数目时,可以使用信号量对象,即CSemaphore类的对象。 C
20、Semaphore的一个对象保存了对当前访问某一指定资源的线程的计数值,该计数值是当前还可以使用该资源的线程的数目。,39,第10章 多线程编程,CSemaphore类的构造函数原型: CSemaphore(LONG lInitialCount = 1, LONG lMaxCount = 1, LPCTSTR pstrName=NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL); 参数lInitialCount为信号量对象的初始计数值,即可访问线程数目的初始值;参数lMaxCount为信号量对象计数值的最大值,该参数决定了同一时刻可访问由信号量
21、保护的资源的线程最大数目;后两个参数在同一进程中使用一般为NULL。,40,第10章 多线程编程,【例10.8】建立一个基于对话框的应用程序Li10_8,该应用程序中包含3个线程。一个线程向数组中写“A”,第二个线程向数组中写“B”,第三个线程向数组中写“C”,使用CSemaphore类保证在同一时刻最多只能有两个线程能访问共享对象数组。程序运行时,出现如下图所示应用程序界面。,41,第10章 多线程编程,10.5.4 使用CEvent 类,CEvent类提供了对事件的支持。事件是一个允许一个线程在某种情况发生时,唤醒另外一个线程的同步对象。事件告诉线程何时去执行某一给定的任务,从而使多个线程流平滑。,42,第10章 多线程编程,在MFC中,CEvent类对象有两种类型:人工事件和自动事件。 一个自动的CEvent对象在被至少一个线程释放后会自动返回到无信号状态;而人工的CEvent对象获得信号后,释放可利用线程,但直到
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 厂房屋面保温施工方案
- 企业数据安全保障方案
- 城市基础设施规划与管理考试
- 2026年深圳市特发集团有限公司校园招聘考试备考试题及答案解析
- 2026年中国电信集团有限公司北京分公司校园招聘笔试备考题库及答案解析
- 2026年中国邮政集团有限公司宁夏回族自治区分公司校园招聘笔试模拟试题及答案解析
- 2024-2025学年度燃气职业技能鉴定考试彩蛋押题及答案详解(新)
- 2025-2026学年人教版七年级历史下册中国古代史复习卷(含答案解析)
- 2026浙江宁波卫生职业技术学院人才(劳务)派遣实验员招聘1人考试参考试题及答案解析
- 2025-2026学年人教版七年级化学上册物质分类单元测试卷(含答案)
- 红莲大桥施工方案(3篇)
- 安徽省江南十校2026届高三3月联考数学试卷(含解析)
- 2025-2025高考电化学真题
- 安康职业技术学院《基础医学选论》2025-2026学年第一学期期末试卷
- 2025-2030中国浮吊行业市场发展趋势与前景展望战略分析研究报告
- 《城市地质风险评价技术要求》编制说明
- 制作红绿灯 课件
- 2024-2030年中国粉尘检测仪行业未来发展趋势及前景调研分析报告
- 《无人机飞行操控技术(微课版)》全套教学课件
- 2024年新改版青岛版(六三制)四年级下册科学全册知识点
- 高中数学专题讲座课件
评论
0/150
提交评论