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

加入VIP,免费下载
 

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

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

下载须知

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

版权提示 | 免责声明

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

天津科技大学操作系统实验.docx

1、天津科技大学操作系统实验2012-2013学年第一学期计算机操作系统实验报告专 业:软件工程班 级:111033学 号:11103325姓 名:孟翔提交日期:2013年11月27日实验一 Windows多线程1实验二 Windows线程同步机制 5实验三 Windows线程通信9实验四 银行家算法模拟15实验五 页面置换算法模拟22实验一 Windows多线程【开发语言及实现平台或实验环境】C+/C#Microsoft Visual Studio 6.0/ Microsoft Visual Studio .NET 【实验目的】(1) 进一步理解操作系统的并发性;(2) 了解Windows线程创

2、建方法,并通过查阅资料理解各参数的含义;(3) 了解多线程程序设计方法,并进行简单应用。【实验要求】(1) 逐程序进行简要分析、运行各程序并仔细阅读注释;(2) 查阅MSDN或其他资料,掌握相关系统调用使用方法和参数含义;(3) 完成实验报告。【相关知识】一、核对象(一) 核对象的概念核对象是核分配的一个存块,这种存块是一个数据结构,表示核对象的各种特征。并且只能由核来访问。应用程序若需要访问核对象,需要通过操作系统提供的函数来进行,不能直接访问核对象(Windows从安全性方面来考虑的)。核对象通过Create*来创建,返回一个用于标识核对象的句柄,这些句柄(而不是核对象)可在创建进程围使用

3、,不能够被传递到其他进程中被使用。(二) 核对象使用的计数因为核对象的所有者是核,而不是进程,所以何时撤销核对象由核决定,而核做这个决定的依据就是该核对象是否仍然被使用。那么如何判断核对象是否被使用呢?可以通过核对象的“使用计数”属性,一旦这个值变成0了,核就可以释放该对象了。(三) 创建核对象1、进程与句柄表每个进程在初始化的时候,将被分配一个句柄表,该句柄表中只存储核对象的句柄,不存储用户对象的句柄。句柄表的详细结构微软没有公布,但是大致包含三个容:核对象句柄,核对象地址,访问屏蔽标志。2、创建核对象及操作系统部机制利用CreateSomeObject的函数来创建核对象。调用该函数的时候核

4、就为该对象分配一个存块,并进行初始化,然后核再扫描该进程的句柄表,初始化一条记录并放在句柄表中。3、进程中使用核对象的部机制假设函数F使用某个核对象,其参数为Handle1,则该函数部需要查找该进程的句柄表,找出参数句柄对应的记录,然后才能使用该核对象。(四) 关闭核对象无论进程怎样创建核对象,在不使用该对象的时候都应当通过bool CloseHandle(HANDLE hobj)来向操作系统声明结束对该对象的访问。为什么叫声明呢?是因为此时也许还有其他进程对该对象的访问,操作系统可能并不立即释放该对象。操作系统需要做的是:从进程的句柄表中删除该核对象的记录,另外再考察该核对象的使用计数以决定

5、是否需要释放该对象。(五)核对象的共享说到共享,与之孪生的就是共享权限。Windows核对象的共享有三种方式:1、继承式共享(父子进程间)只有当进程是父子关系的时候,才能使用此种方式的共享。特别要注意的是继承的是核对象的句柄,核对象本身是不具备继承性。要达到这种继承的效果需要做以下几件事:在进程创建核对象的时候,需要一个安全结构sa(SECURITY_ATTRIBUTES类型,以向OS声明对象的访问方式)作为参数。继承式共享需要将结构的成员sa.bInheritHandle设置为TRUE。此时OS部的处理式将进程的句柄表中的该对象的访问屏蔽字段设置成“可继承”。在创建子进程(CreatePro

6、cess函数)时,设置创建参数bInheritHandles为TRUE。表示被创建的子进程可以继承父进程中的所有可继承核对象。OS部的处理是:复制父进程句柄表中的记录到子进程的句柄表中,并使用相同的句柄值;为核对象的使用计数器加1。特别说明:子进程能够继承的的核对象仅局限于父进程创建它的时候所拥有的可继承核对象。子进程诞生后,父进程再搞出什么可继承的东西,子进程是不能用的。这就需要在子进程中使用继承的核对象的时候需要慎重,以确定核对象是否已被继承了。利用SetHandleinformation方法可以随时修改核对象句柄的一些属性,目前公开的句柄属性有两种,一种是该句柄是否能被继承,另一种是该句

7、柄是否能被关闭。2、同名共享同名共享,不需要共享进程之间存在父子关系。但局限于核对象是否支持这种共享方式。创建核对象的Create函数中是否包含pszName是该核对象是否支持同名共享的标志。 方法一:当Process1通过CreateObject(”someName”)创建了一个名字为someName的核对象后,Process2也调用了CreateObject(”someName”),此时核的动作是:在全局中查询发现已经存在someName1的对象;为Process2的句柄表添加一条Ojbect的记录,使用的句柄不确定;为someName这个Object的引用计数器加1。方法二:Proces

8、s2使用OpenObject(”someName”)的方式来获得对名someName的Object的句柄。用这种Open方法的时候,需要提供一个参数让OS鉴权,以判定是否能够以参数指定的方式来访问核对象。3、复制核对象的句柄的方式共享跨进程边界的核对象共享的另外一个方法是通过DuplicateHandle来复制核对象句柄。如果要将ProcessS中的对象拷贝到ProcessT中则调用DuplicateHandle的进程一定要有对这两个进程的访问权,即句柄表中拥有这两个进程核对象的句柄记录。二、线程的一般概念进程只是线程的容器,从来不执行任何东西;线程总是在某个进程中被创建;线程在进程的地址空间

9、中执行代码;线程们共享进程中的所有核对象。三、线程的创建HANDLE CreateThread(PSECURITY_ATTRIBUTES psa,DWORD cbStack,PTHREAD_START_ROUTINE pfnStartAddr,PVOID pvParam,DWORD fdwCreate,PDWORD pdwThreadID);调用CreateThread后,OS进行如下几个动作:生成一个线程核对象;在进程空间为线程分配堆栈空间。因为线程的环境同于其所在进程的环境,所以创建的线程可以访问进程中的所有资源,包括线程中所有的核对象。四、线程销亡(一)终止线程的方式 线程函数返回(最好

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

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

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

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

14、析原因:1-2.cpp文件使用的是时间片轮转方法调度的主线程、线程1、线程2.因此不需要sleep语句就可将主线程调度。因为在两个线程中存在共享变量,因此执行结果出现不可再现性。(3) 阅读和理解1-3.cpp文件中的程序运行一次1-3.cpp的结果为:将主进程的sleep可用,运行结果为:将两个子函数中注释掉的Sleep语句让其可用,再多次运行:多次运行修改后的程序结果为:分析原因:子函数添加sleep语句后会在之前结果上多出销售0号票的情况,这是因为程序中只要票号大于0便继续执行线程。实验二 Windows线程同步机制【开发语言及实现平台或实验环境】C+/C#Microsoft Visua

15、l Studio 6.0/ Microsoft Visual Studio .NET【实验目的】(1) 了解Windows线程同步机制;(2) 了解互斥体,并通过查阅资料理解互斥体对象的使用方法; (3) 了解事件,并通过查阅资料理解事件对象的使用方法;(4) 了解关键区,并通过查阅资料理解关键区对象的使用方法;(5) 了解信号量,并通过查阅资料理解信号量对象的使用方法;(6) 利用Windows线程同步机制,模拟生产者消费者问题。【实验要求】(1) 逐程序进行简要分析、运行各程序并仔细阅读注释;(2) 查阅MSDN或其他资料,掌握相关系统调用使用方法和参数含义;(3) 完成实验报告。【相关知

16、识】一、Windows线程同步机制Windows下提供了多种核对象实现线程、进程间的同步和互斥,常用的有:1、 关键区(临界区Critical Section)关键区不是核对象,在用户态实现了同一进程中线程的互斥。由于使用时不需要从用户态切换到核心态,所以速度很快(X86系统上约为20个指令周期),但其缺点是不能跨进程同步,同时不能指定阻塞时的等待时间,只能无限等待。使用关键区的方法则使同步管理的效率更高。使用时先定义一个CRITICAL SECTION结构的排斥区对象,在进程使用之前调用如下函数对对象进行初始化: VOID InitializeCriticalSection(LPCRITIC

17、AL_SECTION); 当一个线程使用排斥区时,调用函数:EnterCriticalSection或者TryEnterCriticalSection;当要求占用、退出排斥区时,调用函数LeaveCriticalSection,释放对排斥区对象的占用,供其他线程使用。2、 互斥体(Mutex)互斥体实现了和关键区类似的互斥功能,但区别在于:互斥体是核对象,可以实现跨进程互斥,但需要在用户态和核心态之间切换,速度比关键区慢得多(X86系统上约为600个指令周期),同时可以指定阻塞时的等待时间。Mutex对象的状态在它不被任何线程拥有时才有信号,而当它被拥有时则无信号。Mutex对象很适合用来协调

18、多个线程对共享资源的互斥访问。可按下列步骤使用该对象:首先,建立互斥体对象,得到句柄:HANDLE CreateMutex();然后,在线程可能产生冲突的区域前(即访问共享资源之前)调用WaitForSingleObject,将句柄传给函数,请求占用互斥对象: dwWaitResult=WaitForSingleObject(hMutex,5000L);共享资源访问结束,释放对互斥体对象的占用:ReleaseMutex(hMutex);互斥体对象在同一时刻只能被一个线程占用,当互斥体对象被一个线程占用时,若有另一线程想占用它,则必须等到前一线程释放后才能成功。3、事件(Event)事件也是核对

19、象,具有“信号态”和“无信号态”两种状态。当某一线程等待一个事件时,如果事件为信号态,将继续执行,如果事件为无信号态,那么线程被阻塞。线程能够指定阻塞时的等待时间。例如:只有在通信端口缓冲区收到数据后,监视线程才被激活。事件对象是用CreateEvent函数建立的。该函数可以指定事件对象的类和事件的初始状态。如果是手工重置事件,那么它总是保持有信号状态,直到用ResetEvent函数重置成无信号的事件。如果是自动重置事件,那么它的状态在单个等待线程释放后会自动变为无信号的。用SetEvent可以把事件对象设置成有信号状态。在建立事件时,可以为对象命名,这样其他进程中的线程可以用OpenEven

20、t函数打开指定名字的事件对象句柄。4、信号量(Semaphore)信号量是一个资源计数器,当某线程获取某信号量时,信号量计数首先减1,如果计数小于0,那么该线程被阻塞;当某县城释放某信号量时,信号量计数首先加1,如果计数小于或等与0,那么唤醒某被阻塞的线程并执行之。对信号量的总结如下: 如果计数器m大于0,表示还有m个资源可以访问,此时信号量线程等待队列中没有线程被阻塞,新的线程访问资源也不会被阻塞; 如果计数器m等与0,表示没有资源可以访问,此时信号量线程等待队列中没有线程被阻塞,但新的线程访问资源会被阻塞; 如果计数器m小于0,表示没有资源可以访问,此时信号量线程等待队列中有abs(m)个

21、线程被阻塞,新的线程访问资源会被阻塞;信号量常被用于保证对多个资源进行同步访问。可按下列步骤使用该对象:首先,创建信号对象:HANDLE CreateSemaphoreQ;或者打开一个信号对象:HANDLE OpenSemaphoreQ; 然后,在线程访问共享资源之前调用:WaitForSingleObject;共享资源访问完成后,应释放对信号对象的占用:ReleaseSemaphoreQ;二、生产者消费者模型生产者消费者模型是指: 生产者进行生产将物品放入仓库,同一时间只能有一个生产者将物品放入仓库,如果仓库满,生产者等待。 消费者从仓库中取出物品,同一时间只能有一个消费者取出物品,如果仓库

22、空,消费者等待; 生产者将物品放入仓库时消费者不能同时取; 消费者取物品时生产者不能放入物品;总之,就是生产者群体或消费者群体部是互斥的,两个群体之间是同步的。当只有一个生产者、消费者时,由于同一群体部不需要互斥,所以只需在群体之间实现同步即可。例如可以使用两个Event/CriticalSection/Mutex/Semaphore实现同步;如果有多个生产者和消费者,那么情况会复杂些,需要一个Event/CriticalSection/Mutex实现线程之间的互斥,需要两个Semaphore实现两个线程群体间的同步。【实验步骤】(1) 阅读和理解2-1(mutex).cpp文件中的程序,运行

23、2-1(mutex).cpp,认真观察结果。然后将两个子函数中注释掉的Sleep语句让其可用,再多次运行,认真观察结果,不会出现销售出0号票的情况。比较修改程序前后运行结果发生的变化,并分析其原因。(2) 2-2(event).cpp、2-3(critical_section).cpp的处理方式同(1)。分析:修改之前,在指定暂停的时间sleep(1000)Sleep(1000);/要保证售完40票之前线程不退出,thread1和thread2随机售票,出现多种情况;将两个子函数中注释掉的sleep(1)语句让其可用后,thread1和thread2交替售票,即thread1在其暂停的时间sl

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

25、onsumer只能执行一次;将两个子函数中注释掉的while语句让其可用后,producer和consumer在指定暂停时间sleep(20),随机循环获得共享对象的所有权,进行生产或消费,从而出现多种结果。(4) 阅读和理解2-4(Producer_Consumer)1.cpp文件中的程序,运行2-4(Producer_Consumer)1.cpp,认真观察结果。实验三 Windows线程通信【开发语言及实现平台或实验环境】C+/C#Microsoft Visual Studio 6.0/ Microsoft Visual Studio .NET 【实验目的】(1) 了解Window线程通信

26、方法;(2) 了解匿名管道,并通过查阅资料理解匿名管道的使用方法;(3) 了解命名管道,并通过查阅资料理解命名管道的使用方法;【实验要求】(1) 逐程序进行简要分析、运行各程序并仔细阅读注释;(2) 查阅MSDN或其他资料,掌握相关系统调用使用方法和参数含义;(3) 完成实验报告。【相关知识】Windows应用程序间数据通讯的基本方式有四种。最简单的是利用剪切板;另一种是DDE(Dynamic Data Exchange动态数据交换),它利用一种公共的协议实现两个或多个应用程序之间的通讯;再者是通过存映射文件,存映射可以将一个进程的一段虚拟地址映射为一个文件,然后其它的进程可以共享该段虚拟地址

27、;最后就是通过管道与邮路实现进程间数据通信。管道(pipe)是进程用来通讯的共享存区域。一个进程往管道中写入信息,而其它的进程可以从管道中读出信息。如其名,管道是进程间数据交流的通道。 管道的类型有两种:匿名管道和命名管道。匿名管道是不命名的,它最初用于在本地系统中父进程与它启动的子进程之间的通信。命名管道更高级,它由一个名字来标识,以使客户端和服务端应用程序可以通过它进行彼此通信。而且,Win32命名管道甚至可以在不同系统的进程间使用,这使它成为许多客户/服务器应用程序的理想之选。 就像水管连接两个地方并输送水一样,软件的管道连接两个进程并输送数据。一个一个管道一旦被建立,它就可以象文件一样

28、被访问,并且可以使用许多与文件操作同样的函数。可以使用CreateFile函数获取一个已打开的管道的句柄,或者由另一个进程提供一个句柄。使用WriteFile函数向管道写入数据,之后这些数据可以被另外的进程用ReadFile函数读取。管道是系统对象,因此管道的句柄在不需要时必须使用CloseHandle函数关闭。 匿名管道只能单向传送数据,而命名管道可以双向传送。管道可以以比特流形式传送任意数量的数据。命名管道还可以将数据集合到称为消息的数据块中。命名管道甚至具有通过网络连接多进程的能力。但遗憾的是Windows9X不支持创建命名管道,它只能在Windows NT系列(如Windows NT,

29、Windows 2000,Windows XP)的操作系统上创建。 当讨论管道时,通常涉及到两个进程:客户进程和服务进程。服务进程负责创建管道。客户进程连接到管道。服务进程可以创建一个管道的多个实例,以此支持多个客户进程。 匿名管道用以下函数创建:BOOL CreatePipe( PHANDLE hReadPipe, / 用于读操作的句柄 PHANDLE hWritePipe, / 用于写操作的句柄 LPSECURITY_ATTRIBUTES lpPipeAttributes, / 描述安全信息的一个结构 DWORD nSize / 管道大小 ); 命名管道用以下函数创建:HANDLE Cre

30、ateNamedPipe( LPCTSTR lpName, / 管道名 DWORD dwOpenMode, / 管道打开方式 DWORD dwPipeMode, / 管道模式 DWORD nMaxInstances, / 该管道最大的实例数量 DWORD nOutBufferSize, / 输出缓冲区大小 DWORD nInBufferSize, / 输入缓冲区大小 DWORD nDefaultTimeOut, / 指定默认的超时时间 LPSECURITY_ATTRIBUTES lpSecurityAttributes / 描述安全信息的一个结构 ); 管道由以下函数删除:BOOL CloseHandle( HANDLE hObject / 管道句柄 );其它的

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1