收藏 分享(赏)

操作系统-课程设计指导书new.doc

上传人:dreamzhangning 文档编号:2285982 上传时间:2018-09-09 格式:DOC 页数:73 大小:1.68MB
下载 相关 举报
操作系统-课程设计指导书new.doc_第1页
第1页 / 共73页
操作系统-课程设计指导书new.doc_第2页
第2页 / 共73页
操作系统-课程设计指导书new.doc_第3页
第3页 / 共73页
操作系统-课程设计指导书new.doc_第4页
第4页 / 共73页
操作系统-课程设计指导书new.doc_第5页
第5页 / 共73页
点击查看更多>>
资源描述

1、操作系统课程设计指导书1操作系统课程设计指导书1. 操作系统课程设计1.1 课程的性质和目的“操作系统基础”是计算机专业的核心专业课, “操作系统课程设计”是理解和巩固操作系统基本理论、原理和方法的重要的实践环节。 操作系统课程主要讲述的内容是多道操作系统的原理与技术,与其它计算机原理、编译原理、汇编语言、计算机网络、程序设计等专业课程关系十分密切。本课程设计的目的综合应用学生所学知识,建立系统和完整的计算机系统概念,理解和巩固操作系统基本理论、原理和方法,掌握多道程序设计基本技能。实验的目的:(1) 掌握进程和线程的概念;(2) 掌握进程控制原语或进程控制系统调用的使用;(3) 掌握多道程序

2、设计的基本理论、方法和技术;(4) 掌握相关语言进程控制的函数及 win98 或 windows2000 的进程控制的 API 函数和 MFC 的使用; (5) 培养学生多道程序设计的能力。1.2 课程的内容计算机操作系统是计算机系统中最不可缺少的、最常用的软件,也是核心的、最接近于计算机硬件的软件。计算机操作系统是计算机专业及其相关专业的主要的基础课程之一,其内容综合了各种操作系统的结构、设计思想、方法、技术和理论,其特点是内容繁多、概念抽象,因此造成理解困难、掌握不易。现代操作系统最为核心的概念是多道程序、进程和线程,它们对于操作系统的初学者掌握尤其不易。本课程设计的内容为“多道程序间的协

3、同操作” ,其指导思想是通过这个课程设计掌握多道程序的基本要点,解决进程和线程概念的理解难点,以利用基本概念和原理的进行多道程序设计为重点,在有限的一周时间内,利用诸如 VC+或 Java 掌握多道程序及其进程同步和互斥的设计的基本方法, 达到能用、会用、巧用的效果。1.3 学时分配和辅导 (1)基本任务简介、原理讲解 2 学时(2)软件设计 4 学时(3)上机编程、调试 24 学时(4)检查考核 2 学时每小班大约 30 人,每小班至少配备一名指导教师跟综辅导答疑,解决技术难题。要求指导教师熟悉多道程序间的协同操作、进程同步和互斥的原理,具有 VC+或 Java 程序设计的经验。操作系统课程

4、设计指导书22课程设计的任务2.1 基本任务要求题目 1:多道程序缓冲区协调操作如下图所示,有 10 个 PUT 操作要不断循环地向 Buffer1 送数据,有一个 Move 操作要不断地将 Buffer1 的数据取到 Buffer2,有 20 个 GET 操作要不断地从 Buff2 中取数据。BUFF1 是 10,BUFF2 的容量是 20, PUT、 MOVE、 GET 每次操作一个数据,为了在操作的过程中要保证数据不丢失,每个 Buffer 每次只能接受一个 PUT 或一个 Move 或一个 Get,多个操作不能同时操作同一 BUFFER。设计一个多道程序完成上述操作。试用、原语协调 P

5、UT、 MOVE、GET 的操作,并说明每个信号量的含义、初值和值的范围。PUT MOVE GET 图 1 Buffer 操作题目 2:多道程序间协同操作(自拟)学生自拟设计一个题目,可以是个游戏,可以解决一个简单的实际问题的解决,也可以是客观世界中事物处理的模拟,但要求能够反映多道程序间协同操作,采用多进程或多线程机制设计和运行,尽量体现进程间的同步和互斥关系。2.2 开发环境、技术、工具和工期(1) 建议使用 windowsXP、windows2000、Linux 或 Unix 操作系统,采用的编程语言为 VC、 VB、Java 、Delphi 、.NET 或 C+;(2) 采用多道程序设

6、计技术实现;没有直接对 thread and process 支持的语言,考虑使用 API 函数;(3) 一周之内完成。2.3 基本功能要求(1) 显示 Buffer 的操作过程;(2) 可以确定 Buffer 的容量、PUT、GET、COPY 操作的个数;(3) 自行确定放数据的速度,取数据的速度;(4) 实时显示每个 Buffer 中数据的个数,已放入 Buffer 的数据个数,已取的数据个数;(5) 程序运行结束,显示汇总数据:总的运行时间;Buffer2 Buffer1操作系统课程设计指导书3Buffer 中数据的个数;已放入 BUFFER 的数据个数;已放已取的数据个数;平均 buf

7、fer 中的数据个数。 。 。 。 。 。可以根据题目的基本要求进行丰富的创意和想象。2.4 运行要求(1) 经调试后程序能够正常运行,采用多进程或多线程方式运行,界面尽量体现多道程序的特点、进程间的同步和互斥关系。(2) 本程序可运行在 win98,XP 、Win2000 、Win2003、 Linux 或 Unix 操作系统下,可安装到任意路径下。2.5 提交的材料(1) 提交软件安装盘;(2) 源程序;(3) 设计说明书(电子版):格式要求见 4.10 节描述;(4) 使用说明书(电子版):格式要求见 4.10 节描述。2.6 评分和验收标准 2.6.1 评分标准(1) 软件演示及讲解

8、45 分(2) 设计报告 35 分(3) 使用手册 10 分(4) 注释及良好的程序设计风格 10 分2.6.2 验收标准教师根据设计报告、软件的运行演示和学生回答问题的情况评定成绩。(1)设计报告规范、完整,概念原理论述清楚、软件设计结构合理,独立完成设计,软件运行正常,能够突出表现多道程序运行的特点,回答问题准确明了,可以评为优秀(A) 。(2)设计报告规范、完整,概念原理论述清楚、软件设计结构合理,独立完成、软件基本运行正常,能够表现多道程序运行的特点,回答问题正确,可以评为良(B)。(3)设计报告规范、概念原理论述基本清楚、软件设计结构合理,基本独立完成,软件基本运行正常,基本能够表现

9、多道程序运行的特点,回答问题部分正确,可以评为中良(C)。(4)设计报告基本规范、概念原理论述基本清楚、软件设计结构基本合理,部分独立完成,软件基本可以运行,基本能够表现多道程序运行的特点,回答问题部分正确,可以评为及格(D)。(5)设计报告不规范、概念原理论述不清楚、软件设计结构不合理,大部分不能独立完成,软件基本不能运行,回答问题大部分不正确,可以评为不及格(E)。操作系统课程设计指导书43设计的基本步骤(1) 需求分析查找相关技术资料,了解基本原理,根据题目要求创意软件的功能。.(2) 设计软件的界面程序运行界面要求使用中文或中英文对照.。(3) 总体设计确定基本的技术路线:面向过程还是

10、面向对象;确定软件的总体结构、模块关系、总体流程;确立要创立的进程或线程;确定开发要使用的语言环境;要解决的关键技术问题。(4) 详细设计确定要使用的进程操作的函数、原语、API,掌握它们的使用的参数和返回值。确定模块内部的流程和实现算法;确定要设计的过程、构件、类、对象、函数和它们的参数。(5) 编码设计建立设计编程的环境;注意编程的风格的规范。(6) 实际数据运行测试检查程序是否有错误;检查界面是否美观;检查操作是否方便;检查提供的信息是否清晰;检查性能是否稳定。4设计说明书内容要求4.1 概述目的;主要完成的任务;使用的开发工具;解决的主要问题。4.2 使用的基本概念和原理多道程序;进程

11、;线程;同步和互斥的概念。操作系统课程设计指导书54.3 总体设计确定基本的技术路线:面向过程还是面向对象;确定软件的总体结构、模块关系、总体流程;确立要创立的进程或线程。4.4 详细设计确定要利用的进程操作的函数、原语、API,掌握它们的使用的参数和返回值,要给出具体的名称和参数及其解释;确定模块内部的流程和实现算法;确定要设计的过程、构件、类、对象、函数和它们的参数,要给出具体的名称和参数及其解释。4.5 编码设计开发环境的设置和建立;程序设计时要注意的事项;关键构件/插件的特点和使用;主要程序的代码设计及注释;如果使用、原语协调 PUT、 MOVE、GET 的操作,说明每个信号量的含义、

12、初值和值的范围;解决的技术难点、经常犯的错误。4.6 测试时出现过的问题及其解决方法4.7 总结详细列出已经课程设计的完成情况;未完成的部分;收获、经验、教训和感受等。4.8 参考文献列出你所用的参考文献,包括 Web 上的资源。4.9 格式要求(1) 论文开本为 A4,页边距为设置:上下分别为 3cm,左右分别为 2.9cm 和 2.8cm;(2) 报告书标题用小 2 号黑体字,横向居中排放;(3) 1 级标题用小 3 号黑体;(4) 2 级标题用 4 号黑体;(5) 3 级标题用小 4 号黑体;(6) 正文用 5 号宋体字,行间距为最小值 18 磅;(7) 各层次标题均不得置于页面的最后一

13、行,即不允许“背题”;操作系统课程设计指导书6(8) 图下方要有图号和图名,表上方要有表号和表名;(9) 参考文献编写项目和顺序规定如下:序号 作者.书名出版地: 出版者,出版年:引用部分起止页序号 作者.文章名.学术刊物名,年,卷(期):引用部分起止页表 1 层次代号及说明层次名称 示例 说明全文标题 XXXX 名居中排,章序用阿拉伯数字1 级标题 1 2 级标题 1.1 3 级标题 1.1.1 题序顶格书写,与标题间空一字,下面阐述内容另起一段5 用户使用说明书5.1 基本功能5.2 需要运行的环境5.3 安装5.4 运行5.5 操作6 技术指导6.1 进程与线程进程是一个可执行的程序,由

14、私有虚拟地址空间、代码、数据和其他操作系统资源进程组成。一个应用程序可以有一个或多个进程,一个进程可以有一个或多个线程,其中一个是主线程。动态性是进程最基本的特性。线程是操作系统分时调度分配 CPU 时间的基本实体,是进程的一个实体,是被系统独立调度和分派的基本单位,线程基本上不拥有自己的资源,只拥有一点点在运行中必不可少的资源(如程序计数器、一组寄存器和栈) ,但它可与同属于一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程;同一进程中的多个线程之间可以并发执行。由于创建新进程必须加载代码,而线程要执行的代码已经被映射到进程的地址空间,所以创建、执行线程的速度比进程

15、更快。一个进程的所有线程共享进程的地址空间和全局变量,所以简化了线程之间的通讯。操作系统课程设计指导书76.2 VC+相关函数6.2.1 Win32 的进程与线程处理因为 MFC 没有提供类处理进程,所以直接使用了 Win32 API 函数。1. 进程的创建调用 CreateProcess 函数创建新的进程,运行指定的程序。CreateProcess 的原型如下:BOOL CreateProcess(LPCTSTR lpApplicationName,LPTSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURIT

16、Y_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCTSTR lpCurrentDirectory,LPSTARTUPINFO lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation);其中:lpApplicationName 指向包含了要运行模块名字的字符串;lpCommandLine 指向命令行字符串;lpProcessAttributes 描述进程的安全性属性;lpThreadAttri

17、butes 描述进程初始线程(主线程)的安全性属性;bInHeritHandles 表示子进程(被创建的进程)是否可以继承父进程的句柄。可以继承的句柄有线程句柄、有名或无名管道、互斥对象、事件、信号量、映像文件、普通文件和通讯端口等;还有一些句柄不能被继承,如内存句柄、DLL 实例句柄、GDI 句柄、URER 句柄等等。子进程继承的句柄由父进程通过命令行方式或者进程间通讯(IPC)方式由父进程传递给它。dwCreationFlags 表示创建进程的优先级类别和进程的类型。创建进程的类型分控制台进程、调试进程等;优先级类别用来控制进程的优先级别,分为Idle、Normal 、 High、Real

18、_time 四个类别。lpEnviroment 指向环境变量块,环境变量可以被子进程继承。lpCurrentDirectory 指向表示当前目录的字符串,当前目录可以继承。lpStartupInfo 指向 StartupInfo 结构,控制进程的主窗口的出现方式。lpProcessInformation 指向 PROCESS_INFORMATION 结构,用来存储返回的进程信息。从其参数可以看出创建一个新的进程需要指定的信息。若进程创建成功的话,返回一个进程信息结构类型的指针。进程信息结构如下:typedef struct _PROCESS_INFORMATION HANDLE hProces

19、s;HANDLE hThread;DWORD dwProcessId;DWORD dwThreadId;PROCESS_INFORMATION; 进程信息结构包括进程句柄,主线程句柄,进程 ID,主线程 ID。操作系统课程设计指导书82. 进程的终止进程在以下情况下终止:(1) 调用 ExitProcess 结束进程;(2) 进程的主线程返回,隐含地调用 ExitProcess 导致进程结束;(3) 进程的最后一个线程终止;(4) 调用 TerminateProcess 终止进程;(5) 当要结束一个 GDI 进程时,发送 WM_QUIT 消息给主窗口,当然也可以从它的任一线程调用 ExitP

20、rocess。3. 线程的创建 使用 CreateThread 函数创建线程,CreateThread 的原型如下:HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId);其中:lpThreadAttributes 表示创建线程的安全属性;dwStackSize 指定线程栈的尺寸,如果为 0 则与进

21、程主线程栈相同;lpStartAddress 指定线程开始运行的地址;lpParameter 表示传递给线程的 32 位的参数;dwCreateFlages 表示是否创建后挂起线程 (取值 CREATE_SUSPEND),ResumeThread 继续执行;lpThreadId 用来存放返回的线程 ID。4. 线程的优先级别 进程的每个优先级类包含了五个线程的优先级水平。在进程的优先级类确定之后,可以改变线程的优先级水平。用 SetPriorityClass 设置进程优先级类,用 SetThreadPriority 设置线程优先级水平。Normal 级的线程可以被除了 Idle 级以外的任意线

22、程抢占。5. 线程的终止 以下情况终止一个线程:(1) 调用了 ExitThread 函数; (2) 线程函数返回:主线程返回导致 ExitProcess 被调用,其它线程返回导致ExitThread 被调用; (3) 调用 ExitProcess 导致进程的所有线程终止; (4) 调用 TerminateThread 终止一个线程; (5) 调用 TerminateProcess 终止一个进程时,导致其所有线程的终止。 当用 TerminateProcess 或者 TerminateThread 终止进程或线程时, DLL 的入口函数DllMain 不会被执行(如果有 DLL 的话) 。6.

23、 线程局部存储 如果希望每个线程都可以有线程局部(Thread local)的静态存储数据,可以使用 TLS 线程局部存储技术。TLS 为进程分配一个 TLS 索引,进程的每个线程通过这个索引存取自己操作系统课程设计指导书9的数据变量的拷贝。TLS 对 DLL 是非常有用的。当一个新的进程使用 DLL 时,在 DLL 入口函数 DllMain中使用 TlsAlloc 分配 TLS 索引,TLS 索引就作为进程私有的全局变量被保存;当该进程的新的线程使用 DLL 时(Attahced to DLL) ,DllMain 给它分配动态内存并且使用 TlsSetValue把线程私有的数据按索引保存。D

24、LL 函数可以使用 TlsGetValue 按索引读取调用线程的私有数据。TLS 函数如下: DWORD TlsAlloc() 在进程或 DLL 初始化时调用,并且把返回值(索引值)作为全局变量保存。 BOOL TlsSetValue( DWORD dwTlsIndex,LPVOID lpTlsValue);其中:dwTlsIndex 是 TlsAlloc 分配的索引。lpTlsValue 是线程在 TLS 槽中存放的数据指针,指针指向线程要保存的数据。线程首先分配动态内存并保存数据到此内存中,然后调用 TlsSetValue 保存内存指针到 TLS 槽。 LPVOID TlsGetValue

25、( DWORD dwTlsIndex);其中:dwTlsIndex 是 TlsAlloc 分配的索引。当要存取保存的数据时,使用索引得到数据指针。 BOOL TlsFree( DWORD dwTlsIndex);其中:dwTlsIndex 是 TlsAlloc 分配的索引。当每一个线程都不再使用局部存储数据时,线程释放它分配的动态内存。在TLS 索引不再需要时,使用 TlsFree 释放索引。7. 线程同步 同步可以保证在一个时间内只有一个线程对某个资源(如操作系统资源等共享资源)有控制权。共享资源包括全局变量、公共数据成员或者句柄等。同步还可以使得有关联交互作用的代码按一定的顺序执行。Win

26、32 提供了一组对象用来实现多线程的同步。这些对象有两种状态:获得信号(Signaled)或者没有或则信号(Not signaled)。线程通过Win32 API 提供的同步等待函数(Wait functions)来使用同步对象。一个同步对象在同步等待函数调用时被指定,调用同步函数地线程被阻塞(blocked),直到同步对象获得信号。被阻塞的线程不占用 CPU 时间。同步对象主要有:Critical_section(临界区) ,Event(事件) ,Mutex(互斥对象) ,Semaphores(信号量) ,下面着重解释怎么使用这些同步对象。临界区对象 操作系统课程设计指导书10定义一个临界区

27、对象 cs:CRITICAL_SECTION cs;初始化该对象:InitializeCriticalSection(初始化时把对象设置为 NOT_SINGALED,表示允许线程使用资源。如果一段程序代码需要对某个资源进行同步保护,则这是一段临界区代码。在进入该临界区代码前调用 EnterCriticalSection 函数,这样,其他线程都不能执行该段代码,若它们试图执行就会被阻塞。完成临界区的执行之后,调用 LeaveCriticalSection 函数,其他的线程就可以继续执行该段代码。如果该函数不被调用,则其他线程将无限期的等待。 事件对象 首先,调用 CreateEvent 函数创建

28、一个事件对象,该函数返回一个事件句柄。然后,可以设置(SetEvent)或者复位(ResetEvent)一个事件对象,也可以发一个事件脉冲(PlusEvent) ,即设置一个事件对象,然后复位它。复位有两种形式:自动复位和人工复位。在创建事件对象时指定复位形式。自动复位:当对象获得信号后,就释放下一个可用线程(优先级别最高的线程;如果优先级别相同,则等待队列中的第一个线程被释放) 。人工复位:当对象获得信号后,就释放所有可利用线程。最后,使用 CloseHandle 销毁创建的事件对象。 互斥对象 首先,调用 CreateMutex 创建互斥对象;然后,调用等待函数,可以的话利用关键资源;最后

29、,调用 RealseMutex 释放互斥对象。互斥对象可以在进程间使用,但临界区对象只能用于同一进程的线程之间。 信号量对象 在 Win32 中,信号量的数值变为 0 时给以信号。在有多个资源需要管理时可以使用信号量对象。首先,调用 CreateSemaphore 创建一个信号量;然后,调用等待函数,如果允许的话,则利用关键资源;最后,调用 RealeaseSemaphore 释放信号量对象。此外,还有其它句柄可以用来同步线程: 文件句柄(FILE HANDLES)命名管道句柄(NAMED PIPE HANDELS)控制台输入缓冲区句柄(CONSOLE INPUT BUFFER HANDLES

30、)通讯设备句柄(COMMUNICTION DEVICE HANDLES)进程句柄(PROCESS HANDLES)线程句柄(THREAD HANDLES)例如,当一个进程或线程结束时,进程或线程句柄获得信号,等待该进程或者线程结束的线程被释放。8. 等待函数 Win32 提供了一组等待函数用来让一个线程阻塞自己的执行,等待函数分三类。等待单个对象的(FOR SINGLE OBJECT)函数,包括:SignalObjectAndWait;WaitForSingleObject;WaitForSingleObjectEx。函数参数包括同步对象的句柄和等待时间等。在以下情况下等待函数返回:同步对象获

31、得信号时返回;等待时间达到了返回。操作系统课程设计指导书11如果等待时间不限制(Infinite),则只有同步对象获得信号才返回;如果等待时间为 0,则在测试了同步对象的状态之后马上返回。等待多个对象的(FOR MULTIPLE OBJECTS)的函数,包括:WaitForMultipleObjects;WaitForMultipleObjectsEx;MsgWaitForMultipleObjects;MsgWaitForMultipleObjectsEx。函数参数包括同步对象的句柄,等待时间,是等待一个还是多个同步对象等等。在以下情况下等待函数返回:一个或全部同步对象获得信号时返回(在参数

32、中指定是等待一个或多个同步对象) ;等待时间达到了返回:如果等待时间不限制(Infinite),则只有同步对象获得信号才返回;如果等待时间为 0,则在测试了同步对象的状态之后马上返回。可以发出提示的函数(ALTERABLE)函数,包括:MsgWaitForMultipleObjectsEx;SignalObjectAndWait;WaitForMultipleObjectsEx;WaitForSingleObjectEx;这些函数主要用于重叠(Overlapped) 的 I/O(异步 I/O) 。6.2.2 MFC 的线程处理在 Win32 API 的基础之上,MFC 提供了处理线程的类和函数

33、。处理线程的类是CWinThread,函数是 AfxBeginThread、AfxEndThread 等。 CWinThread 是 MFC 线程类,它的成员变量 m_hThread 和 m_hThreadID 是对应的 Win32 线程句柄和线程 ID。MFC 明确区分两种线程:用户界面线程(User interface thread)和工作者线程(Worker thread)。用户界面线程一般用于处理用户输入并对用户产生的事件和消息作出应答。工作者线程用于完成不要求用户输入的任务,如耗时计算。Win32 API 并不区分线程类型,它只需要知道线程的开始地址以便它开始执行线程。MFC 为用户

34、界面线程特别地提供消息泵来处理用户界面的事件。 CWinApp 对象是用户界面线程对象的一个例子,CWinApp 从类 CWinThread 派生并处理用户产生的事件和消息。1. 创建用户界面线程 通过以下步骤创建一个用户界面线程:(1) 从 CWinThread 派生一个有动态创建能力的类。使用 DECLARE_DYNCREATE和 IMPLEMENT_DYNCREATE 宏来支持动态创建; (2) 覆盖 CWinThread 的一些虚拟函数。其中:函数 InitInstance 是必须覆盖的,ExitInstance 通常是要覆盖的; (3) 使用 AfxBeginThread 创建 MF

35、C 线程对象和 Win32 线程对象。如果创建线程时没有指定 CREATE_SUSPENDED,则开始执行线程; (4) 如果创建线程是指定了 CREATE_SUSPENDED,则在适当的地方调用函数ResumeThread 开始执行线程。 2. 创建工作者线程 (1) 程序员不必从 CWinThread 派生新的线程类,只需要提供一个控制函数,由线程启动后执行该函数;(2) 使用 AfxBeginThread 创建 MFC 线程对象和 Win32 线程对象,如果创建线程时没有指定 CREATE_SUSPENDED(创建后挂起) ,则创建的新线程开始执行;操作系统课程设计指导书12(3) 如果

36、创建线程是指定了 CREATE_SUSPENDED,则在适当的地方调用函数ResumeThread 开始执行线程;(4) 虽然程序员没有从 CWinThread 派生类,但是 MFC 给工作者线程提供了缺省的CWinThread 对象。3. AfxBeginThread 用户界面线程和工作者线程都是由 AfxBeginThread 创建的。现在,考察该函数:MFC提供了两个重载版的 AfxBeginThread,一个用于用户界面线程,另一个用于工作者线程,分别有如下的原型和过程。 用户界面线程的 AfxBeginThread 的原型如下:CWinThread* AFXAPI AfxBeginT

37、hread(CRuntimeClass* pThreadClass,int nPriority, UINT nStackSize, DWORD dwCreateFlags,LPSECURITY_ATTRIBUTES lpSecurityAttrs);其中:参数 1 是从 CWinThread 派生的 RUNTIME_CLASS 类;参数 2 指定线程优先级,如果为 0,则与创建该线程的线程相同;参数 3 指定线程的堆栈大小,如果为 0,则与创建该线程的线程相同;参数 4 是一个创建标识,如果是 CREATE_SUSPENDED,则在悬挂状态创建线程,在线程创建后线程挂起,否则线程在创建后开始线

38、程的执行;参数 5 表示线程的安全属性。工作者线程的 AfxBeginThread 的原型如下:CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam,int nPriority, UINT nStackSize, DWORD dwCreateFlags,LPSECURITY_ATTRIBUTES lpSecurityAttrs)其中:参数 1 指定控制函数的地址;参数 2 指定传递给控制函数的参数;参数 3、4、5 分别指定线程的优先级、堆栈大小、创建标识、安全属性,含义同用户界面线程。4.

39、AfxBeginThread 创建线程的流程 不论哪个 AfxBeginThread,首先都是创建 MFC 线程对象,然后创建 Win32 线程对象。在创建 MFC 线程对象时,用户界面线程和工作者线程的创建分别调用了不同的构造函数。用户界面线程是从 CWinThread 派生的,所以,要先调用派生类的缺省构造函数,然后调用 CWinThread 的缺省构造函数。5. CreateThread 和_AfxThreadEntry MFC 使用 CWinThread:CreateThread 创建线程,不论对工作者线程或用户界面线程,都指定线程的入口函数是_AfxThreadEntry。_AfxT

40、hreadEntry 调用 AfxInitThread 初始化线程。操作系统课程设计指导书13CreateThread 和_AfxThreadEntry 在线程的创建过程中使用同步手段交互等待、执行。CreateThread 由创建线程执行,_AfxThreadEntry 由被创建的线程执行,两者通过两个事件对象(hEvent 和 hEvent2)同步。在创建了新线程之后,创建线程将在 hEvent 事件上无限等待直到新线程给出创建结果;新线程在创建成功或者失败之后,触发事件 hEvent 让父线程运行,并且在 hEven2 上无限等待直到父线程退出 CreateThread 函数;父线程(

41、创建线程)因为 hEvent 的置位结束等待,继续执行,退出 CreateThread 之前触发 hEvent2 事件;新线程(子线程)因为 hEvent2 的置位结束等待,开始执行控制函数(工作者线程)或者进入消息循环(用户界面线程) 。MFC 在线程创建中使用了如下数据结构:struct _AFX_THREAD_STARTUP/传递给线程启动的参数(IN)_AFX_THREAD_STATE* pThreadState;/父线程的线程状态CWinThread* pThread; /新创建的 MFC 线程对象DWORD dwCreateFlags; /线程创建标识_PNH pfnNewHand

42、ler; /新线程的句柄HANDLE hEvent; /同步事件,线程创建成功或失败后置位HANDLE hEvent2; /同步事件,新线程恢复执行后置位/返回给创建线程的参数,在新线程恢复执行后赋值BOOL bError; /如果创建发生错误,TRUE;该结构作为线程开始函数的参数被传递给_beginthreadex 函数来创建和启动线程。_beginthreadex 函数是“C”的线程创建函数,具有如下原型:unsigned long _beginthreadex(void *security,unsigned stack_size,unsigned ( _stdcall *start_a

43、ddress )( void * ),void *arglist,unsigned initflag,unsigned *thrdaddr );6. 实现线程的消息循环 在 MFC 中,消息循环是由线程完成的。一般地,可以使用 MFC 缺省的消息循环(即使用函数 CWindThrad:Run) ,但是,有些时候需要程序员自己实现一个线程的消息循环,比如在用户界面线程进行一个长时间计算处理或者等待另一个线程时。一般有如下形式:while ( bDoingBackgroundProcessing) MSG msg;while ( :PeekMessage( :PostQuitMessage( );

44、break;操作系统课程设计指导书14LONG lIdle = 0;while ( AfxGetApp()-OnIdle(lIdle+ ) );程序员实现线程的消息循环有两个好处,一是顾及了 MFC 的 Idle 处理机制;二是在长时间的处理中可以响应用户产生的事件或者消息。在同步对象上等待其它线程时,也可以使用同样的方式,只要把条件 bDoingBackgroundProcessing 换成如下形式:WaitForSingObject(hHandleOfEvent,0) = WAIT_TIMEOUT 即可。MFC 处理线程和进程时还引入了一个重要的概念:状态,如线程状态 (Thread St

45、ate)、进程状态(Process State)、模块状态(Module State)等。6.3 多线程编程问题在这部分将较为详细的讲解 6.2 中函数的应用及其遇到的问题。6.3.1 问题的提出编写一个耗时的单线程程序。新建一个基于对话框的应用程序 SingleThread,在主对话框 IDD_SINGLETHREAD_DIALOG 添加一个按钮,ID 为 IDC_SLEEP_SIX_SECOND,标题为“延时 6 秒” ,添加按钮的响应函数,代码如下: void CSingleThreadDlg:OnSleepSixSecond() Sleep(6000); /延时 6 秒编译并运行应用程

46、序,单击“延时 6 秒”按钮,你就会发现在这 6 秒期间程序就像“死机”一样,不再响应其它消息。这仅仅是一个小小的程序,如果在一个较大系统中多次出现这样的事件,势必会浪费很多计算机资源。为了更好地处理这种耗时的操作,我们有必要学习多线程编程。 6.3.2 Win32 API 多线程编程例程 1 MultiThread1建立一个基于对话框的工程 MultiThread1,在对话框 IDD_MULTITHREAD1_DIALOG中加入两个按钮和一个编辑框,两个按钮的 ID 分别是 IDC_START,IDC_STOP ,标题分别为“启动”, “停止 ”,IDC_STOP 的属性选中 Disable

47、d;编辑框的 ID 为 IDC_TIME ,属性选中 Read-only。 在 MultiThread1Dlg.h 文件中添加线程函数声明: void ThreadFunc();注意,线程函数的声明应在类 CMultiThread1Dlg 的外部。 在类 CMultiThread1Dlg 内部添加 protected 型变量: HANDLE hThread;DWORD ThreadID;分别代表线程的句柄和 ID。 在 MultiThread1Dlg.cpp 文件中添加全局变量 m_bRun: volatile BOOL m_bRun;m_bRun 代表线程是否正在运行。现在要留意到全局变量

48、m_bRun 是使用 volatile 修饰符的, volatile 修饰符的作用是告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值可被外操作系统课程设计指导书15部改变。对于多线程引用的全局变量来说,volatile 是一个非常重要的修饰符。编写线程函数: void ThreadFunc()CTime time;CString strTime;m_bRun=TRUE;while(m_bRun)time=CTime:GetCurrentTime();strTime=time.Format(“%H:%M:%S“);:SetDlgItemText(AfxGetMainWnd

49、()-m_hWnd,IDC_TIME,strTime);Sleep(1000);该线程函数没有参数,也不返回函数值。只要 m_bRun 为 TRUE,线程一直运行。双击 IDC_START 按钮,完成该按钮的消息函数: void CMultiThread1Dlg:OnStart() hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFunc,NULL, 0,GetDlgItem(IDC_START)-EnableWindow(FALSE);GetDlgItem(IDC_STOP)-EnableWindow(TRUE);双击 IDC_STOP 按钮,完成该按钮的消息函数: void CMultiThread1Dlg:OnStop() m_bRun=FALSE;GetDlgItem(IDC_START)-EnableWindow(TRUE);GetDlgItem(IDC_STOP)-Enab

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

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

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报