《操作系统实验-读者写者》由会员分享,可在线阅读,更多相关《操作系统实验-读者写者(29页珍藏版)》请在金锄头文库上搜索。
1、概述p实验目的p实验内容p实验要求p实验环境p实验分析与设计p相关API函数p输入数据与运行结果说明1对读者写者问题的实现进行分析,并进一步分别对读者优先和写者优先两种算法的核心思想作了探讨和程序设计的提示。对程序设计中将会用到的API函数的功能及参数进行说明,并对其中重要的几个函数作讲解。实验目的1、熟悉多线程编程2、熟悉使用信号量机制解决同步问题2实验内容创建一个控制台进程。此进程包含n个线程。用这n个线程来表示n个读者或写者。每个线程按相应测试数据文件(后面有介绍)的要求进行读写操作。用信号量机制分别实现读者优先和写者优先的读者-写者问题。3实验要求读者-写者问题的读写操作限制(包括读者
2、优先和写者优先):1) 写-写互斥,即不能有两个写者同时进行写操作。2) 读-写互斥,即不能同时有一个线程在读,而另一个线程在写。3) 读-读允许,即可以有一个或多个读者在读。比喻:把摘花比作写,赏花比作读,那么写-写互斥就像两个或多个人不能同时摘同一朵花,否则就出现争抢场面。类似的,那么读-写互斥就像一个人正在赏花时,另一个人却在摘这朵花,导致矛盾的产生。不同的是,对于一朵花而言,多个人可以同时观赏,并不会产生矛盾。4实验要求(续) 读者优先的附加限制:如果一个读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。 写者优先的附加限制:如果一个读者申请进行读操作时已有另
3、一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。 运行结果显示要求:要求在每个线程创建、发出读写操作申请、开始读写操作和结束读写操作时分别显示一行提示信息,以确定所有处理都遵守相应的读写操作限制。5实验环境1、一台WINDOWS 2000/NT/XP操作系统的计算机2、Visual C+编程平台6实验分析与设计进程和线程(1/2) 在Windows32位操作系统中,所谓多任务是指系统可以同时运行多个进程,而每个进程也可以同时执行多个线程。 所谓进程就是应用程序的运行实例。每个进程都有自己私有的虚拟地址空间。每个进程都有一个主线程,但可以建立另外的线程。进程中的线
4、程是并发执行的,每个线程占用CPU的时间由系统来划分。我们可以把线程看成是操作系统分配CPU时间的基本实体。7实验分析与设计进程和线程(2/2) 进程中的所有线程共享进程的虚拟地址空间,这意味着所有线程都可以访问进程的全局变量和资源。这一方面为编程带来了方便,但另一方面也容易造成冲突。 虽然在进程中进行费时的工作不会导致系统的挂起,但这会导致进程本身的挂起。所以,如果进程既要进行长期的工作,又要响应用户的输入,那么它可以启动一个线程来专门负责费时的工作,而主线程仍然可以与用户进行交互。8实验分析与设计线程同步(1/3) 1、线程的同步 多线程的使用会产生一些新的问题,主要是如何保证线程的同步执
5、行。多线程应用程序需要使用同步对象和等待函数来实现同步。同步问题是实现远程数据采集或远程自动控制编程中的关键技术问题。9实验分析与设计线程同步(2/3)2、同步的原因 由于同一进程的所有线程共享进程的虚拟地址空间,并且线程的中断是汇编语言级的,所以可能会发生两个线程同时访问同一个对象(包括全局变量、共享资源、API 函数和MFC对象等)的情况,这有可能导致程序错误。例如,如果一个线程在未完成对某一大尺寸全局变量的读操作时,另一个线程又对该变量进行了写操作,那么第一个线程读入的变量值可能是一种修改过程中的不稳定值。 属于不同进程的线程在同时访问同一内存区域或共享资源时,也会存在同样的问题。因此,
6、在多线程应用程序中,常常需要采取一些措施来同步线程的执行。10实验分析与设计线程同步(3/3)3、同步的方法 由于线程间需要同步机制,才能协调运行。在Win32 编程中,主要由WINDOWS API函数来实现,这部分知识将会在后面讨论。11实验分析与设计同步对象(1/4) 同步对象用来协调多线程的执行,它可以被多个线程共享。线程的 等待函数用同步对象的句柄作为参数,同步对象应该是所有要使用 的线程都能访问到的。同步对象的状态要么是有信号的,要么是无 信号的。同步对象主要有三种:事件、mutex 和信号灯。12实验分析与设计同步对象(2/4) 事件对象(Event)是最简单的同步对象,它包括有信
7、号和无信号两种状态。在线程访问某一资源之前,也许需要等待某一事件的发生,这时用事件对象最合适。例如,只有在通信端口缓冲区收到数据后,监视线程才被激活。13实验分析与设计同步对象(3/4) Mutex 对象的状态在它不被任何线程拥有时是有信号的,而当它被拥有时则是无信号的。mutex 对象很适合用来协调多个线程对共享资源的互斥访问(mutually exclusive)。14实验分析与设计同步对象(4/4) 信号灯对象维护一个从 0 开始的计数,在计数值大于 0 时对象是有信号的,而在计数值为 0 时则是无信号的。信号灯对象可用来限制对共享资源进行访问的线程数量。线程用CreateSemapho
8、re函数来建立信号灯对象,在调用该函数时,可以指定对象的初始计数和最大计数。在建立信号灯时也可以为对象起个名字,别的进程中的线程可以用OpenSemaphore函数打开指定名字的信号灯句柄。15实验分析与设计临界区 临界区 (Critical Seciton) 与 mutex 的功能类似,但它只能由同一进程中的线程使用。临界区可以防止共享资源被同时访问。 进程负责为临界区分配内存空间,临界区实际上是一个CRITICAL_SECTION型的变量,它一次只能被一个线程拥有。在线程使用临界区之前,必须调用 InitializeCriticalSection 函数将其初始化。如果线程中有一段临界的代码
9、不希望被别的线程中断,那么可以调用 EnterCriticalSection 函数来申请临界区的所有权,在运行完临界代码后再用LeaveCriticalSection 函数来释放所有权。如果在调用EnterCriticalSection 时临界区对象已被另一个线程拥有,那么该函数将无限期等待所有权。16实验分析与设计分析(1/3) 由题目要求可以知道,这是一个实现多线程的使用,要求多个读者线程和多个写者线程共享读写临界区,而各个读者线程共享读进程资源,各个写线程共享写进程资源,所以这里包含了两个层次的共享,不妨把读写线程共享的临界区称为全局临界区,所有读线程共享的读进程的临界资源称为局部读临界
10、区,所有写线程共享的写进程的临界资源称为局部写临界区。具体的关系如图所示:17实验分析与设计分析(2/3) 18读写线程共享的内存读写临界区读进程共享资源写进程共享资源读线程1读线程2读线程3写线程1写线程2写线程3实验分析与设计分析(3/3) 根据题目的要求还可以知道,在一个进程下的多个线程的并发情况:同是读进程的不同线程可以同时访问读写全局临界区,但是同是写进程的不同线程每次只能一个访问该读写全局临界区,还有就是读写线程不能同时访问读写全局临界区。19实验分析与设计设计20 根据以上的进程和线程的理解以及对线程同步机制的分析,结合本次实验的特点,设计出了以下的方案: 读线程间和写线程间对各
11、自局部共享资源的访问修改采用Mutex对象,结合WaitForSingleObject 保证互斥操作。 读线程与写线程争用全局临界资源采用临界区(Critical Seciton)。 统管读写线程的线程采用WaitForMultipleObjects 保证等待所有的线程结束。相关API函数等待函数(1/2)21 等待函数只有在作为其参数的一个或多个同步对象产生信号时才会返回。在超过规定的等待时间后,不管有无信号,函数也都会返回。在等待函数未返回时,线程处于等待状态,此时线程只消耗很少的CPU时间。使用等待函数即可以保证线程的同步,又可以提高程序的运行效率。DWORD WaitForSingle
12、Object (HANDLE hHandle, DWORD dwMilliseconds);参数 hHandle 是同步对象的句柄。参数dwMilliseconds 是以毫秒为单位的超时间隔,如果该参数为0,那么函数就测试同步对象的状态并立即返回,如果该参数为INFINITE,则超时间隔是无限的。相关API函数等待函数(2/2)22 DWORD WaitForMultipleObjects (DWORD nCount, CONST HANDLE* lpHandles, BOOL fWaitAll, IDWORD dwMilliSeconds) ;函数功能:函数功能:WaiForMultiple
13、Objects函数当下列条件之一满足时返回:(1)任意一个或全部指定对象处于信号态;(2)超时间隔已过。返回值:返回值:如果函数调用成功,返回值表明引起函数返回的事件。注:该函数及后面的函数介绍中皆省略了对参数的介绍,请参考文档。相关API函数其他函数(1/4)23 HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlag,LPDWORD l
14、pThreadId);函数功能:函数功能:该函数创建一个在调用进程的地址空间中执行的线程。返回值:返回值:若函数调用成功,返回值为新线程的句柄;若函数调用失败,返回值为NULL。相关API函数其他函数(2/4)24 VOID ExitThread (DWORD dwExitCode);函数功能:函数功能:该函数结束一个线程。返回值:返回值:无。VOID Sleep (DWORD dwMilliseconds);函数功能:函数功能:该函数对于指定的时间间隔挂起当前的执行线程。返回值:返回值:该函数没有返回值。相关API函数其他函数(3/4)25 HANDLE CreateMutex(LPSECU
15、RITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner,LPCTSTR lpName);函数功能:函数功能:该函数创建有名或者无名的互斥对象。返回值:返回值:如果函数调用成功,返回值是互斥对象句柄;如果函数调用之前,有名互斥对象已存在,那么函数给已存在的对象返回一个句柄,并且函数GetLastError返回ERROR_ALREADY_EXISTS,否则,调用者创建互斥对象。Bool ReleaseMutex (HANDLE hMutex);函数功能:函数功能:该函数放弃指定互斥对象的所有权。返回值:返回值:如果函数调用成功,那么返回值是非零值;
16、如果函数调用失败,那么返回值是零值。若想获得更多错误信息,请调用GetLastError函数。相关API函数其他函数(4/4)26VOID InltlalizeCriticalSection(LPCRITICAL_SECTION IpCritiCalSection); 函数功能:函数功能:该函数初始化临界区对象。返回值:返回值:无。 VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);函数功能:函数功能:该函数是等待指定临界区对象的所有权。当调用线程被 赋予所有权时,该函数返回。返回值:返回值:无。VOID Leave
17、CriticalSection(LPCRITICAL_SECTION lpCriticalSection);函数功能:函数功能:该函数释放指定临界区对象的所有权。返回值:返回值:无。 数据输入格式27 测试数据文件包括n行测试数据,分别描述创建的n个线程是读者还是写者,以及读写操作的开始时间和持续时间。每行测试数据包括四个字段,各个字段间用空格分隔。 第一字段为一个正整数,表示线程序号。 第二字段表示相应线程角色,R表示读者,W表示写者。 第三字段为一个正数,表示读写操作的开始时间:线程创建后,延迟相应时间(单位为秒)后发出对共享资源的读写申请。 第四字段为一个正数,表示读写操作的持续时间。 当线程读写申请成功后,开始对共享资源的读写操作,该操作持续相应时间后结束,并释放共享资源。由于牵涉格式的问题,最好在记事本中手工逐个键入数据。运行结果28下面是一个测试数据文件的例子:1 R 3 52 W 4 53 R 5 24 R 6 55 W 5.1 3选择选择1运行结果运行结果Thanks for your attentionTHE END!29