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

加入VIP,免费下载
 

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

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

下载须知

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

版权提示 | 免责声明

本文(天津科技大学操作系统实验1-5.doc)为本站会员(dreamzhangning)主动上传,道客多多仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知道客多多(发送邮件至docduoduo@163.com或直接QQ联系客服),我们立即给予删除!

天津科技大学操作系统实验1-5.doc

1、课 程 号:1002060106适用专业:计算机各专业制 定 人:吴江红教 研 室:计算机科学与技术教研室计算机科学与信息工程学院2012 年5 月操作系统实验指导书前言操作系统是计算机的核心和灵魂。操作系统软件的设计对整个计算机的功能和性能起着至关重要的作用,所以此门课也是必不可少的,是面向计算机科学与技术、网络工程、软件工程等大多数计算机专业本科生和研究生开设的一门计算机专业课程。操作系统是计算机系统的核心, 操作系统课程是计算机科学与技术专业的重要必修课。本课程的目的是使学生掌握现代计算机操作系统的基本原理、基本设计方法及实现技术,具有分析现行操作系统和设计、开发实际操作系统的基本能力。

2、本课程的理论性强,内容抽象,特别是进程管理,需要通过严密的逻辑思维来想象微观时间世界中的处理机调度与运行。通过学习使学生掌握计算机操作系统的基本原理及组成;计算机操作系统的基本概念和相关的新概念、名词及术语;了解计算机操作系统的发展特点、设计技巧和方法;对常用计算机操作系统(Dos、Windows 和 Unix 或 Linux) 会进行基本的操作使用。实验要求为了顺利完成编译原理课程实验,学生应做到: (1) 熟练掌握一种高级程序设计语言。(2) 实验前,认真学习教材以及实验指导书的相关内容,提前做好实验准备。(3) 每次实验先分析后编程,在实验报告中应写明自己的编程思路和设计流程。(4) 实

3、验结束一周后提交实验报告。实验报告内容应包括:实验目的、实验内容、设计思路和流程框图,源程序(含注释)清单、测试结果以及实验总结。(5) 遵守机房纪律,服从辅导教师指挥,爱护实验设备。实验的验收将分为两个部分。第一部分是上机操作,随机抽查程序运行和即时提问;第二部分是提交书面的实验报告。此外杜绝抄袭现象,一经发现雷同,双方成绩均以0分计算。目 录实验一 Windows 多线程 1 实验二 Windows 线程同步机制 5实验三 Windows 线程通信 9实验四 银行家算法模拟 15实验五 页面置换算法模拟 221实验一 Windows 多线程【开发语言及实现平台或实验环境】C+/C#Micr

4、osoft Visual Studio 6.0/ Microsoft Visual Studio .NET 【实验目的】(1) 进一步理解操作系统的并发性;(2) 了解 Windows 线程创建方法,并通过查阅资料理解各参数的含义;(3) 了解多线程程序设计方法,并进行简单应用。【实验要求】(1) 逐程序进行简要分析、运行各程序并仔细阅读注释;(2) 查阅 MSDN 或其他资料,掌握相关系统调用使用方法和参数含义;(3) 完成实验报告。【相关知识】一、内核对象(一) 内核对象的概念内核对象是内核分配的一个内存块,这种内存块是一个数据结构,表示内核对象的各种特征。并且只能由内核来访问。应用程序若

5、需要访问内核对象,需要通过操作系统提供的函数来进行,不能直接访问内核对象(Windows 从安全性方面来考虑的)。内核对象通过 Create* 来创建,返回一个用于标识内核对象的句柄,这些句柄(而不是内核对象)可在创建进程范围内使用,不能够被传递到其他进程中被使用。(二) 内核对象使用的计数因为内核对象的所有者是内核,而不是进程,所以何时撤销内核对象由内核决定,而内核做这个决定的依据就是该内核对象是否仍然被使用。那么如何判断内核对象是否被使用呢?可以通过内核对象的“使用计数”属性,一旦这个值变成 0 了,内核就可以释放该对象了。(三) 创建内核对象1、进程与句柄表每个进程在初始化的时候,将被分

6、配一个句柄表,该句柄表中只存储内核对象的句柄,不存储用户对象的句柄。句柄表的详细结构微软没有公布,但是大致包含三个内容:内核对象句柄,内核对象地址,访问屏蔽标志。2、创建内核对象及操作系统内部机制2利用 CreateSomeObject 的函数来创建内核对象。调用该函数的时候内核就为该对象分配一个内存块,并进行初始化,然后内核再扫描该进程的句柄表,初始化一条记录并放在句柄表中。3、进程中使用内核对象的内部机制假设函数 F 使用某个内核对象,其参数为 Handle1,则该函数内部需要查找该进程的句柄表,找出参数句柄对应的记录,然后才能使用该内核对象。(四) 关闭内核对象无论进程怎样创建内核对象,

7、在不使用该对象的时候都应当通过 bool CloseHandle(HANDLE hobj) 来向操作系统声明结束对该对象的访问。为什么叫声明呢?是因为此时也许还有其他进程对该对象的访问,操作系统可能并不立即释放该对象。操作系统需要做的是:从进程的句柄表中删除该内核对象的记录,另外再考察该内核对象的使用计数以决定是否需要释放该对象。(五) 内核对象的共享说到共享,与之孪生的就是共享权限。 Windows 内核对象的共享有三种方式:1、继承式共享(父子进程间)只有当进程是父子关系的时候,才能使用此种方式的共享。特别要注意的是继承的是内核对象的句柄,内核对象本身是不具备继承性。要达到这种继承的效果需

8、要做以下几件事:在进程创建内核对象的时候,需要一个安全结构 sa ( SECURITY_ATTRIBUTES 类型,以向 OS 声明对象的访问方式)作为参数。继承式共享需要将结构的成员 sa.bInheritHandle 设置为 TRUE 。此时 OS 内部的处理式将进程的句柄表中的该对象的访问屏蔽字段设置成“可继承”。在创建子进程( CreateProcess 函数)时,设置创建参数 bInheritHandles 为 TRUE 。表示被创建的子进程可以继承父进程中的所有可继承内核对象。 OS 内部的处理是:复制父进程句柄表中的记录到子进程的句柄表中,并使用相同的句柄值;为内核对象的使用计数

9、器加 1 。特别说明:子进程能够继承的的内核对象仅局限于父进程创建它的时候所拥有的可继承内核对象。子进程诞生后,父进程再搞出什么可继承的东西,子进程是不能用的。这就需要在子进程中使用继承的内核对象的时候需要慎重,以确定内核对象是否已被继承了。利用 SetHandleinformation 方法可以随时修改内核对象句柄的一些属性,目前公开的句柄属性有两种,一种是该句柄是否能被继承,另一种是该句柄是否能被关闭。2、同名共享同名共享,不需要共享进程之间存在父子关系。但局限于内核对象是否支持这种共享方式。创建内核对象的 Create 函数中是否包含 pszName 是该内核对象是否支持同名共享的标志。

10、方法一:当 Process1 通过 CreateObject(”someName”)创建了一个名字为 someName 的内核对象后, Process2 也调用了 CreateObject(”someName”),此时内核的动作是:在全局中查询3发现已经存在 someName1 的对象;为 Process2 的句柄表添加一条 Ojbect 的记录,使用的句柄不确定;为 someName 这个 Object 的引用计数器加 1 。方法二: Process2 使用 OpenObject(”someName” )的方式来获得对名 someName 的 Object的句柄。用这种 Open 方法的时候

11、,需要提供一个参数让 OS 鉴权,以判定是否能够以参数指定的方式来访问内核对象。3、复制内核对象的句柄的方式共享跨进程边界的内核对象共享的另外一个方法是通过 DuplicateHandle 来复制内核对象句柄。如果要将 ProcessS 中的对象拷贝到 ProcessT 中则调用 DuplicateHandle 的进程一定要有对这两个进程的访问权,即句柄表中拥有这两个进程内核对象的句柄记录。二、线程的一般概念进程只是线程的容器,从来不执行任何东西;线程总是在某个进程中被创建;线程在进程的地址空间中执行代码;线程们共享进程中的所有内核对象。三、线程的创建HANDLE CreateThread(P

12、SECURITY_ATTRIBUTES psa,DWORD cbStack,PTHREAD_START_ROUTINE pfnStartAddr,PVOID pvParam,DWORD fdwCreate,PDWORD pdwThreadID);调用 CreateThread 后,OS 进行如下几个动作:生成一个线程内核对象;在进程空间内为线程分配堆栈空间。因为线程的环境同于其所在进程的环境,所以创建的线程可以访问进程中的所有资源,包括线程中所有的内核对象。四、线程销亡(一) 终止线程的方式线程函数返回(最好使用这个方式,可以保证:线程中创建的 C+ 对象正常析构; OS 释放线程堆栈内存;

13、OS 将线程的退出码设置为线程函数的返回值;系统将递减该线程内核对象的的使用计数器【如果此时还有其他引用 ,见下面说明】。) 调用 ExitThread (不能释放 C+ 对象,所以最好不要使用这个方式。另外,如果非要调用也应当调用编译器推荐的,如 _endThread 【 Windows 核心编程 P127 】) 同进程内的其他线程(包括主线程)调用 TerminateThread (被撤销线程得不到通知,不能释放资源,尽量避免这种方式。另外这个函数是个异步函数,返回时,线程不保证已经被撤销,如果要观察线程是否被撤销,应当使用 WaitForSingleObject )包含线程的进程终止(应

14、当避免这种方式)(二) 线程退出时 OS 的行为4线程内的所有用户对象被释放。 线程的退出码从 STILL_ACTIVE 改为传递给 ExitThread 或 TerminateThread 的代码线程内核对象的状态改为“已通知”如果线程为进程中的最后一个线程,则 OS 将进程当作已终止运行线程内核对象的引用计数器减 1 (一旦线程终止了,其他引用改线程内核对象将不能够处理改线程的句柄,但是可以通过调用 GetExitcodeThread 来检查 hThread 代表的线程是否已经终止运行了。)【实验步骤】(1) 阅读和理解1-1.cpp 文件中的程序,多次运行1-1.cpp ,认真观察结果。

15、然后将main函数中注释掉的Sleep语句让其可用,即将其前面的注释号删掉,再多次运行,认真观察结果。比较修改程序前后运行结果发生的变化,并分析其原因。(2) 阅读和理解1-2.cpp 文件中的程序,多次运行1-2.cpp ,认真观察结果。思考为什么1-2.cpp 中可以不需要Sleep语句就可看到各线程都被调度了。(3) 阅读和理解1-3.cpp 文件中的程序,运行1-3.cpp ,认真观察结果。然后将main函数中注释掉的Sleep语句让其可用,即将其前面的注释号删掉,再多次运行,认真观察结果。再将两个子函数中注释掉的Sleep语句让其可用,再多次运行,认真观察结果,可能会出现销售出0号票

16、的情况。比较修改程序前后运行结果发生的变化,并分析其原因。【实验结果与分析】(1) 阅读和理解 1-1.cpp文件中的程序运行一次 1-1.cpp 的结果如下:运行多次 1-1.cpp 的结果如下:将 main 函数中注释掉的 Sleep 语句让其可用,运行结果为:5分析原因:Sleep(0)的作用为语句可观察线程 1 和主线程并发执行。输出结果“main thread is running /thread1 is running”。没有添加的线程 1 运行结束只输出“main thread is running”(2) 阅读和理解 1-2.cpp 文件中的程序运行一次 1-2.cpp 文件的

17、结果如下:运行多次 1-2.cpp 文件的结果如下:分析原因:1-2.cpp 文件使用的是时间片轮转方法调度的主线程、线程 1、线程 2.因此不需要 sleep 语句就可将主线程调度。因为在两个线程中存在共享变量,因此执行结果出现不可再现性。(3) 阅读和理解 1-3.cpp 文件中的程序6运行一次 1-3.cpp 的结果为:将主进程的 sleep 可用,运行结果为:将两个子函数中注释掉的 Sleep 语句让其可用,再多次运行:7多次运行修改后的程序结果为:【 程序说明 】 多线程文件夹下1-1.cpp 文件:简单的多线程示例;1-2.cpp 文件:在 1.cpp 文件中加入循环,使得两个线程

18、交替执行,理解时间片轮转调度,因为8在两个线程中存在共享变量,因此执行结果出现不可再现性。1-3.cpp 文件:编写一个模拟火车站售票系统的程序,多窗口售票可采用多线程技术实现。主线程创建两个线程(即两个售票窗口) 。实验二 Windows线程同步机制【开发语言及实现平台或实验环境】C+/C#Microsoft Visual Studio 6.0/ Microsoft Visual Studio .NET【实验目的】(1) 了解 Windows 线程同步机制;(2) 了解互斥体,并通过查阅资料理解互斥体对象的使用方法; (3) 了解事件,并通过查阅资料理解事件对象的使用方法;(4) 了解关键区

19、,并通过查阅资料理解关键区对象的使用方法;(5) 了解信号量,并通过查阅资料理解信号量对象的使用方法;(6) 利用Windows 线程同步机制,模拟生产者消费者问题。【实验要求】(1) 逐程序进行简要分析、运行各程序并仔细阅读注释;(2) 查阅 MSDN 或其他资料,掌握相关系统调用使用方法和参数含义;(3) 完成实验报告。【相关知识】9一、Windows 线程同步机制Windows 下提供了多种内核对象实现线程、进程间的同步和互斥,常用的有:1、 关键区(临界区 Critical Section)关键区不是内核对象,在用户态实现了同一进程中线程的互斥。由于使用时不需要从用户态切换到核心态,所

20、以速度很快( X86 系统上约为 20 个指令周期),但其缺点是不能跨进程同步,同时不能指定阻塞时的等待时间,只能无限等待。使用关键区的方法则使同步管理的效率更高。使用时先定义一个 CRITICAL SECTION 结构的排斥区对象,在进程使用之前调用如下函数对对象进行初始化:VOID InitializeCriticalSection(LPCRITICAL_SECTION); 当一个线程使用排斥区时,调用函数:EnterCriticalSection 或者 TryEnterCriticalSection;当要求占用、退出排斥区时,调用函数 LeaveCriticalSection,释放对排斥

21、区对象的占用,供其他线程使用。2、 互斥体( Mutex )互斥体实现了和关键区类似的互斥功能,但区别在于:互斥体是内核对象,可以实现跨进程互斥,但需要在用户态和核心态之间切换,速度比关键区慢得多(X86 系统上约为 600 个指令周期),同时可以指定阻塞时的等待时间。Mutex 对象的状态在它不被任何线程拥有时才有信号,而当它被拥有时则无信号。Mutex对象很适合用来协调多个线程对共享资源的互斥访问。可按下列步骤使用该对象:首先,建立互斥体对象,得到句柄:HANDLE CreateMutex();然后,在线程可能产生冲突的区域前(即访问共享资源之前) 调用 WaitForSingleObje

22、ct,将句柄传给函数,请求占用互斥对象:dwWaitResult=WaitForSingleObject(hMutex,5000L);共享资源访问结束,释放对互斥体对象的占用:ReleaseMutex(hMutex);互斥体对象在同一时刻只能被一个线程占用,当互斥体对象被一个线程占用时,若有另一线程想占用它,则必须等到前一线程释放后才能成功。3、事件(Event)事件也是内核对象,具有“信号态”和“无信号态”两种状态。当某一线程等待一个事件时,如果事件为信号态,将继续执行,如果事件为无信号态,那么线程被阻塞。线程能够指定阻塞时的等待时间。例如:只有在通信端口缓冲区收到数据后,监视线程才被激活。

23、事件对象是用 CreateEvent函数建立的。该函数可以指定事件对象的类和事件的初始状态。如果是手工重置事件,那么它总是保持有信号状态,直到用 ResetEvent 函数重置成无信号的事件。如果是自动重置事件,那10么它的状态在单个等待线程释放后会自动变为无信号的。用 SetEvent 可以把事件对象设置成有信号状态。在建立事件时,可以为对象命名,这样其他进程中的线程可以用 OpenEvent 函数打开指定名字的事件对象句柄。4、信号量(Semaphore)信号量是一个资源计数器,当某线程获取某信号量时,信号量计数首先减 1 ,如果计数小于 0 ,那么该线程被阻塞;当某县城释放某信号量时,信

24、号量计数首先加 1 ,如果计数小于或等与 0,那么唤醒某被阻塞的线程并执行之。对信号量的总结如下: 如果计数器 m 大于 0 ,表示还有 m 个资源可以访问,此时信号量线程等待队列中没有线程被阻塞,新的线程访问资源也不会被阻塞; 如果计数器 m 等与 0 ,表示没有资源可以访问,此时信号量线程等待队列中没有线程被阻塞,但新的线程访问资源会被阻塞; 如果计数器 m 小于 0 ,表示没有资源可以访问,此时信号量线程等待队列中有abs ( m )个线程被阻塞,新的线程访问资源会被阻塞;信号量常被用于保证对多个资源进行同步访问。可按下列步骤使用该对象:首先,创建信号对象:HANDLE CreateSe

25、maphoreQ;或者打开一个信号对象:HANDLE OpenSemaphoreQ;然后,在线程访问共享资源之前调用:WaitForSingleObject;共享资源访问完成后,应释放对信号对象的占用:ReleaseSemaphoreQ;二、生产者消费者模型生产者消费者模型是指: 生产者进行生产将物品放入仓库,同一时间只能有一个生产者将物品放入仓库,如果仓库满,生产者等待。 消费者从仓库中取出物品,同一时间只能有一个消费者取出物品,如果仓库空,消费者等待; 生产者将物品放入仓库时消费者不能同时取; 消费者取物品时生产者不能放入物品;总之,就是生产者群体或消费者群体内部是互斥的,两个群体之间是同

26、步的。当只有一个生产者、消费者时,由于同一群体内部不需要互斥,所以只需在群体之间实 现同步即可。例如可以使用两个 Event/CriticalSection/Mutex/Semaphore 实现同步;如果有多个生产者和消费者,那么情况会复杂些,需要一个 Event/CriticalSection/Mutex 实现线程之间的互斥,需要两个 Semaphore 实现两个线程群体间的同步。【实验步骤】(1) 阅读和理解2-1(mutex).cpp文件中的程序,运行2-1(mutex).cpp,认真观察结果。然后将两个11子函数中注释掉的Sleep语句让其可用,再多次运行,认真观察结果,不会出现销售出

27、0号票的情况。比较修改程序前后运行结果发生的变化,并分析其原因。(2) 2-2(event).cpp、2-3(critical_section).cpp的处理方式同(1) 。2-2 122-3 分析:修改之前,在指定暂停的时间sleep(1000)内Sleep(1000);/要保证售完40张票之前线程不退出,thread1和thread2随机售票,出现多种情况;将两个子函数中注释掉的sleep(1)语句让其可用后,thread1和thread2交替售票,即thread1在其暂停的时间 sleep(1)内,thread2 获得了对共享对象hmutex的所有权,开始售票,同理当thread2 在其

28、暂停的时间sleep (1)内,thread1获得了对共享对象hmutex的所有权,开始售票,从而实现了交替售票。(3) 阅读和理解2-4(Producer_Consumer).cpp文件中的程序,运行2-4(Producer_Consumer).cpp ,认真观察结果,先生产后消费。然后将两个子函数中注释掉的while语句让其可用,再多次运行,认真观察结果,生产者和消费者保持同步。比较修改程序前后运行结果发生的变化,并分析其原因。13分析:修改之前,在指定暂停时间sleep(20)内,producer和consumer 只能执行一次;将两个子函数中注释掉的while语句让其可用后,produ

29、cer和consumer在指定暂停时间sleep (20)内,随机循环获得共享对象的所有权,进行生产或消费,从而出现多种结果。(4) 阅读和理解 2-4(Producer_Consumer)1.cpp文件中的程序,运行 2-4(Producer_Consumer)1.cpp,认真观察结果。14【实验思考及总结】进程同步也包括进程的互斥和进程的同步两个方面,使操作系统管理共享资源的一种手段。通过这次实验,体会了线程同步机制的重要性,同时,在选用线程同步机制时也应该根据具体的案例的要求选择合适的线程同步机制,对效率要求很高的程序就应该自己编写效率比较高的线程同步机制。【程序说明】同步文件夹下2-1

30、(mutex).cpp 文件:对 1-3.cpp 中的程序,利用互斥对象实现同步。2-2(event).cpp 文件:对 1-3.cpp 中的程序,利用事件对象实现同步。2-3(critical_section).cpp 文件:对 1-3.cpp 中的程序,利用临界区实现同步。2-4(Producer_Consumer).cpp 文件:模拟一个生产者一个消费者的同步问题。2-4(Producer_Consumer)1.cpp 文件:模拟两个生产者两个消费者的同步问题。15实验三 Windows线程通信【开发语言及实现平台或实验环境】C+/C#Microsoft Visual Studio 6.

31、0/ Microsoft Visual Studio .NET 【实验目的】(1) 了解 Window 线程通信方法;(2) 了解匿名管道,并通过查阅资料理解匿名管道的使用方法;(3) 了解命名管道,并通过查阅资料理解命名管道的使用方法;【实验要求】(1) 逐程序进行简要分析、运行各程序并仔细阅读注释;(2) 查阅 MSDN 或其他资料,掌握相关系统调用使用方法和参数含义;(3) 完成实验报告。【相关知识】Windows应用程序间数据通讯的基本方式有四种。最简单的是利用剪切板;另一种是DDE( Dynamic Data Exchange动态数据交换),它利用一种公共的协议实现两个或多个应用程序

32、之间的通讯;再者是通过内存映射文件,内存映射可以将一个进程的一段虚拟地址映射为一个文件,然后其它的进程可以共享该段虚拟地址;最后就是通过管道与邮路实现进程间数据通信。管道(pipe)是进程用来通讯的共享内存区域。一个进程往管道中写入信息,而其它的进程可以从管道中读出信息。如其名,管道是进程间数据交流的通道。 管道的类型有两种:匿名管道和命名管道。匿名管道是不命名的,它最初用于在本地系统中父进程与它启动的子进程之间的通信。命名管道更高级,它由一个名字来标识,以使客户端和服务端应用程序可以通过它进行彼此通信。而且,Win32命名管道甚至可以在不同系统的进程间使用,这使它成为许多客户/ 服务器应用程

33、序的理想之选。就像水管连接两个地方并输送水一样,软件的管道连接两个进程并输送数据。一个一个管道一旦被建立,它就可以象文件一样被访问,并且可以使用许多与文件操作同样的函数。可以使用CreateFile函数获取一个已打开的管道的句柄,或者由另一个进程提供一个句柄。使用WriteFile函数向管道写入数据,之后这些数据可以被另外的进程用ReadFile函数读取。管道是系统对象,因此管道的句柄在不需要时必须使用CloseHandle函数关闭。16匿名管道只能单向传送数据,而命名管道可以双向传送。管道可以以比特流形式传送任意数量的数据。命名管道还可以将数据集合到称为消息的数据块中。命名管道甚至具有通过网

34、络连接多进程的能力。但遗憾的是Windows9X不支持创建命名管道,它只能在 Windows NT系列(如Windows NT,Windows 2000,Windows XP)的操作系统上创建。当讨论管道时,通常涉及到两个进程:客户进程和服务进程。服务进程负责创建管道。客户进程连接到管道。服务进程可以创建一个管道的多个实例,以此支持多个客户进程。匿名管道用以下函数创建:BOOL CreatePipe(PHANDLE hReadPipe, / 用于读操作的句柄PHANDLE hWritePipe, / 用于写操作的句柄LPSECURITY_ATTRIBUTES lpPipeAttributes,

35、 / 描述安全信息的一个结构DWORD nSize / 管道大小);命名管道用以下函数创建:HANDLE CreateNamedPipe(LPCTSTR lpName, / 管道名DWORD dwOpenMode, / 管道打开方式DWORD dwPipeMode, / 管道模式DWORD nMaxInstances, / 该管道最大的实例数量DWORD nOutBufferSize, / 输出缓冲区大小DWORD nInBufferSize, / 输入缓冲区大小DWORD nDefaultTimeOut, / 指定默认的超时时间LPSECURITY_ATTRIBUTES lpSecurity

36、Attributes / 描述安全信息的一个结构); 管道由以下函数删除:BOOL CloseHandle(HANDLE hObject / 管道句柄);其它的管道函数简介如下:CallNamedPipe:连接到一个命名管道,读取或写入数据之后关闭它。ConnectNamedPipe:服务进程准备好一个连接到客户进程的管道,并等待一个客户进程连接上为止。DisconnectNamedPipe:服务端用来断开与客户端的连接。GetNamedPipeHandleState:获取一个命名管道的状态信息。GetNamedPipeInfo:获取一个命名管道的信息。17PeekNamedPipe:从一个匿

37、名或命名管道中拷贝数据到一个缓冲区。SetNamedPipeHandleState:设置管道的类型及其它状态信息,比如说是比特流还是消息流管道。TransactNamedPipe:从一个消息管道读消息或向其写入消息。WaitNamedPipe:客户进程用来连接到一个命名管道。【实验步骤】(1)匿名管道:先编译 Child 工程,然后运行 Parent 工程,再在 Parent 中创建管道和子进程,然后双方即可通过管道通信。如下图所示。(2)命名管道:Server 和 Client 各自运行,再在 Server 中创建命名管道, 然后在 Client 中连接管18道,最后双方即可通过管道通信。如

38、上图所示。注:相关代码在 *View.cpp 中【实验结果与分析】匿名管道是不命名的,它用于本地系统中父进程与 它启动的子程序之间的通信。而命名管道由一个名字来标识,以使 客户端和服务端应用程序通过它可以进行彼此之间的通信。Windows 中的匿名管道通信机制是一种系统内部高效的数据通信 和同步机制,它不生成额外的文件,又能有效地管理通信过程中的 内存。这种隐藏的数据通信方式为应用程序进程间的通信和同步提 供了极大的灵活性。(实验三选做题目,如果实现了本题目需要交此代码):在客户端输入数据 a 和 b,然后发送到服务器并计算 a+b,然后把计算结果发送到客户端。可以多个客户端与同一个服务器并行

39、通信。界面设计如下:19难点所在:实现的过程比较简单,但有一个难点。原本当服务端使用 ConnectNamedPipe 函数后,如果有客户端连接,就可以直接进行交互。原来在实现过程中,当管道空闲时,管道的线程函数会无限(INFINITE)阻塞。若现在需要停止服务,就必须结束所有的线程,TernimateThread可以作为一个结束线程的方法,但基本不用这个函数。一旦使用这个函数之后,目标线程就会立即结束,但如果此时的目标线程正在操作互斥资源、内核调用、或者是操作共享 DLL 的全局变量,可能会出现互斥资源无法释放、内核异常等现象。这里用重叠 I/0 来解决这个问题,在创建 PIPE 时使用 F

40、ILE_FLAG_OVERLAPPED 标志,这样使用 ConnectNamedPipe 后会立即返回,但线程的阻塞由等待函数 WaitForSingleObject 来实现,等待 OVERLAPPED 结构的事件对象被设置。客户端主要代码:/提交按钮单击事件void CMyDlg:OnSubmit() / 打开管道HANDLE hPipe = CreateFile(“.PipeNamedPipe“, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) ;if ( hPipe =

41、INVALID_HANDLE_VALUE )this-MessageBox ( “打开管道失败,服务器尚未启动,或者客户端数量过多“ ) ;return ;DWORD nReadByte, nWriteByte ;char szBuf1024 = 0 ;sprintf ( szBuf, “%d %d“, this-nFirst, this-nSecond ) ; / 把两个整数(a,b) 格式化为字符串WriteFile ( hPipe, szBuf, strlen(szBuf), / 把数据写入管道memset ( szBuf, 0, sizeof(szBuf) ) ;ReadFile (

42、hPipe, szBuf, 1024, / 读取服务器的反馈信息20sscanf ( szBuf, “%d“, / 把返回信息格式化为整数this-UpdateData ( false ) ;CloseHandle ( hPipe ) ;服务端主要代码:/启动服务void CMyDlg:OnStart() CString lpPipeName = “.PipeNamedPipe“ ;for ( UINT i = 0; i MessageBox ( “创建管道错误!“ ) ;return ;/ 为每个管道实例创建一个事件对象,用于实现重叠 IOPipeInsti.hEvent = CreateE

43、vent ( NULL, false, false, false ) ;/ 为每个管道实例分配一个线程,用于响应客户端的请求PipeInsti.hTread = AfxBeginThread ( ServerThread, this-SetWindowText ( “命名管道实例之服务器 (运行)“ ) ;this-MessageBox ( “服务启动成功 “ ) ;/ 停止服务void CMyDlg:OnStop() DWORD dwNewMode = PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_NOWAIT ;for ( UINT i = 0; i Set

44、WindowText ( “命名管道实例之服务器 “ ) ;this-MessageBox ( “停止启动成功 “ ) ;21/ 线程服务函数UINT ServerThread ( LPVOID lpParameter )DWORD nReadByte = 0, nWriteByte = 0, dwByte = 0 ;char szBufMAX_BUFFER_SIZE = 0 ;PIPE_INSTRUCT CurPipeInst = *(PIPE_INSTRUCT*)lpParameter ;OVERLAPPED OverLapStruct = 0, 0, 0, 0, CurPipeInst.

45、hEvent ;while ( true )memset ( szBuf, 0, sizeof(szBuf) ) ;/ 命名管道的连接函数,等待客户端的连接(只针对 NT)ConnectNamedPipe ( CurPipeInst.hPipe, / 实现重叠 I/0,等待 OVERLAPPED 结构的事件对象WaitForSingleObject ( CurPipeInst.hEvent, INFINITE ) ;/ 检测 I/0 是否已经完成,如果未完成,意味着该事件对象是人工设置,即服务需要停止if ( !GetOverlappedResult ( CurPipeInst.hPipe,

46、/ 从管道中读取客户端的请求信息if ( !ReadFile ( CurPipeInst.hPipe, szBuf, MAX_BUFFER_SIZE, break ;int a, b ;sscanf ( szBuf, “%d %d“, pMyDlg-nFirst = a ;pMyDlg-nSecond = b ;pMyDlg-nResValue = a + b ;memset ( szBuf, 0, sizeof(szBuf) ) ;sprintf ( szBuf, “%d“, pMyDlg-nResValue ) ;/ 把反馈信息写入管道WriteFile ( CurPipeInst.hPi

47、pe, szBuf, strlen(szBuf), pMyDlg-SetDlgItemInt ( IDC_FIRST, a, true ) ;pMyDlg-SetDlgItemInt ( IDC_SECOND, b, true ) ;pMyDlg-SetDlgItemInt ( IDC_RESULT, pMyDlg-nResValue, true ) ;/ 断开客户端的连接,以便等待下一客户的到来DisconnectNamedPipe ( CurPipeInst.hPipe ) ;return 0 ;22实验四 银行家算法模拟【开发语言及实现平台或实验环境】C+/C#Microsoft Visual Studio 6.0/ Microsoft Visual Studio .NET 2003【实验目的】(1)进一步理解利用银行家算法避免死锁的问题;(2)在了解和掌握银行家算法。(3)理解和掌握安全序列、安全性算法【实验内容】(1)编写安全性算法;(2)编写银行家算法,并编制银行家算法通用程序,将调试结果显示在计算机屏幕上,再检测和笔算的一致性

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


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

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

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