操作系统学习课程设计方案_第1页
操作系统学习课程设计方案_第2页
操作系统学习课程设计方案_第3页
操作系统学习课程设计方案_第4页
操作系统学习课程设计方案_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 操作系统课程设计读者写者问题 一、实习要求 在 windows 2000 环境下,创建一个控制台进程,此进程包含n 个线程。用这 n 个线程来表示 n 个读者或写 者。每个线程按相应测试数据文件 (后面有介绍 )的要求进行读写操作。用信号量机制分别实现读者优先和写者 优先的读者写者问题。 读者写者问题的读写操作限制 (包括读者优先和写者优先 ): 1)写写互斥,即不能有两个写者同时进行写操作。 2)读写互斥,即不能同时有一个线程在读,而另一个线程在写。 3)读读允许,即可以有一个或多个读者在读。 读者优先的附加限制:如果一个读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接 开

2、始读操作。 写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须 等到没有写者处于等待状态后才能开始读操作。 运行结果显示要求:要求在每个线程创建、发出读写操作申请、开始读写操作和结束读写操作时分别显示 一行提示信息,以确定所有处理都遵守相应的读写操作限制。 二、测试数据文件格式 测试数据文件包括 n行测试数据,分别描述创建的n个线程是读者还是写者,以及读写操作的开始时间和 持续时间。每行测试数据包括四个字段,各个字段间用空格分隔。第字段为个正整数,表示线程序号。第 二字段表示相应线程角色,R表示读者,W表示写者。第三字段为一个正数,表示读写操作的开始时

3、间:线程 创建后,延迟相应时间 (单位为秒 )后发出对共享资源的读写申请。第四字段为一个正数,表示读写操作的持续 时间。当线程读写申请成功后,开始对共享资源的读写操作,该操作持续相应时间后结束,并释放共享资源。 下面是个测试数据文件的例子: 1 R 3 5 2 W 4 5 3 R 5 2 4 R 6 5 5 W 5.1 3 注意 在创建数据文件时,由于涉及到文件格式问题,最好在记事本中手工逐个键入数据,而不要拷贝粘贴 数据,否则,本示例程序运行时可能会出现不可预知的错误。 三、实习分析 可以将所有读者和所有写者分别存于一个读者等待队列和一个写者等待队列中,每当读允许时,就从读者 队列中释放一个

4、或多个读者线程进行读操作;每当写允许时,就从写者队列中释放一个写者进行写操作。 1. 读者优先 的读者数目,用于确定是否需要释放正在等待的写者线程 写者等待队列中的一个写者 )。每一个读者开始读文件时, mutex来实现对全局变量 readcount修改时的互斥。 另外,为了实现写写互斥,需要增加一个临界区对象 对象的所有权。通过这种方法,也可以实现读写互斥、当 必须申请临界区对象的所有权。 当读者拥有临界区的所有权时,写者阻塞在临界区对象 读者优先指的是除非有写者在写文件,否则读者不需要等待。所以可以用一个整型变量readcou nt记录当前 (当 readcount=0 时,表明所有的读者

5、读完,需要释放 必须修改readcou nt变量。因此需要一个互斥对象 RP_Write 。当写者发出写请求时,必须申请临界区 readcount=1 时 (即第一个读者到来时 ),读者线程也 RP_Write 上。当写者拥有临界区的所有权时,第一 个读者判断完readcount= =1 ”后阻塞在 write上,其余的读者由于等待对 readcount的判断,阻塞在 mutex 上。 2. 写者优先(请根据自己编写的写者优先程序进行分析) 四、相关 API 函数说明 1. CreateThread 函数功能: 该函数创建一个在调用进程的地址空间中执行的线程。 函数原型: HANDLE Cre

6、ateThread (LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId)。 参数: IpThreadAttributes :指向一个LPSECURITY_A TTRIBUTES 结构。该结构决定了返回的句柄是否可被子 进程继承。若 lpThreadAttributes 为 NULL ,则句柄不能被继承。 在 Windows

7、NT 中该结构的 lpSecurityDescriptor 成员定义了新进程的安全性描述符。若 lpThreadAttributes 为 NULL 。则线程获得个默认的安全性描述符。 dwStackSize: 定义原始堆栈提交时的大小 (按字节计 )。系统将该值舍入为最近的页。若该值为0,或小 于默认时提交的大小,默认情况是使用与调用线程同样的大小更多的信息,请看Thread Stack Size。 IpStartAddress: 指向一个 LPTHREAD_START_ROUTINE 类型的应用定义的函数,该线程执行此函数。 该指针还表示远程进程中线程的起始地址。该函数必须存在于远程进程中。

8、 IpParameter : 定义一个传递给该进程的 32 位值。 dwCreationFIags: 定义控制进程创建的附加标志。若定义了 CREATE_SUSPENDED 标志,线程创建时 处于挂起状态,并且直到ResumeThread 函数调用时才能运行。若该值为0,则该线程在创建后立即执行。 IpThreadId :指向个 32位值,它接收该线程的标识符。 返回值: 若函数调用成功,返回值为新线程的句柄;若函数调用失败,返回值为NULL 。 备注: 新进程的句柄创建时设为 THREAD_ALL_ACCESS 访问权限。若未提供安全性描述符,则该句柄可被任何 要求一个线程对象句柄的函数所使

9、用。若提供了安全性描述符,则以后使用该句柄时,将在授权访问以前执行 访问检查。若访问检查拒绝访问,则请求进程不能使用该句柄获得对该线程的访问。 线程从 lpStartAddress 参数定义的函数处开始执行。若该函数返回,系统将默认地认为以调用ExitThread 函 数的方法终止该线程。使用 GetExitcodeThread 函数来获得线程的返回值。 线程创建时拥有 THREAD_PRIORITY_NORMAL 优先权。使用 GetThreadPriority 和 SetThreadPriority 函数 可以获得和设置线程的优先权值。 一个线程终止时。该线程对象被设为发信号状态,以满足在

10、该对象上等待的所有进程。 一个线程对象始终存在于系统中,直到该线程终止,且它所有的句柄都已通过调用CloseHandle 函数关 闭。 2. ExitThread 函数功能: 该函数结束一个线程。 函数原型: VOID ExitThread (DWORD dwExitCode ); 参数: dwExitCode : 定义调用线程的退出代码。使用 GetExitCodeThread 函数来检测一个线程的退出代码。 返回值: 无。 备注: 调用 ExitThread 函数,是结束个线程的较好的方法。调用该函数后(或者直接地调用,或者从一个线程过 程返回 ),当前线程的堆栈取消分配,线程终止。若调用

11、该函数时,该线程为进程的最后一个线程,则该线程的 进程也被终止。 线程对象的状态变为发信号状态,以释放所有正在等待该线程终止的其他线程。线程的终止状态从 STILL_ACTIV ATE 变为 dwExitCode 参数的值。 线程结束时不必从操作系统中移去该线程对象。当线程的最后一个句柄关闭时,该线程对象被删除。 3.Sleep 函数功能: 该函数对于指定的时间间隔挂起当能的执行线程。 函数原型: VOID Sleep (DWORD dwMulliseconds) ; 参数: dwMilliseconds:定义挂起执行线程的时间,以毫秒(ms)为单位。取值为 0时,该线程将余下的时间片交 给处

12、于就绪状态的同一优先级的其他线程。若没有处于就绪状态的同一优先级的其他线程,则函数立即返回, 该线程继续执行。若取值为 INFINITE 则造成无限延迟。 返回值: 该函数没有返回值。 备注: 一个线程可以在调用该函数时将睡眠时间设为0ms,以将剩余的时间片交出。 4. CreateMutex 函数功能: 该函数创建有名或者无名的互斥对象。 函数原型: HANDLE CreateMutex (LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName) 。 参数: lpMutexAttributes :

13、 指向 SECURITY_ATTRIBUTES 结构的指针,该结构决定子进程是否能继承返回句 柄。如果 lpMutexAttributes 为 NULL ,那么句柄不能被继承。 在 Windows NT 中该结构的 LpSecuriyDescriptor 成员指定新互斥对象的安全描述符。如果 lpMutexAttributes 为 NULL ,那么互斥对象获得默认的安全描述符。 bInitialOwner : 指定互斥对象的初始所属身份。如果该值为 TRUE ,并且调用者创建互斥对象,那么调 用线程获得互斥对象所属身份。否则,调用线程不能获得互斥对象所属身份。判断调用者是否创建互斥对象清 参阅

14、返回值部分。 lpName : 指向以 NULL 结尾的字符串,该字符串指定了互斥对象名。该名字的长度小于MAX_PATH 且 可以包含除反斜线()路径分隔符以外的任何字符。名字是区分大小写的。 如果 lpName 与已存在的有名互斥对象名相匹配,那么该函数要求用MUTEX_ALL_ACCESS 权限访问已存 在的对象。在这种情况下,由于参数 bInitialOwner 已被创建进程所设置,该参数被忽略。如果参数 lpMutexAttributes 不为 NULL ,它决定句柄是否解除继承,但是其安全描述符成员被忽略。 如果 lpName 为 NULL ,那么创建的互斥对象无名。 如果 lpN

15、ame 与已存在的事件、信号量、 可等待定时器、作业或者义件映射对象的名字相匹配,那么函数 调用失败,并且 GetLastError 函数返回 ERROR_ALREADY_HANDLE, 其原因是这些对象共享相同的名字空间。 返回值: 如果函数调用成功,返回值是互斥对象句柄;如果函数调用之前,有名互斥对象已存在,那么函数给已存 在的对象返回一个句柄,并且函数 GetLastError 返回 ERROR_ ALREADY_EXISTS 。否则,调用者创建互斥对 象。 如果函数调用失败,则返回值为 NULL 。若想获得更多错误信息,请调用 GetLastError 函数。 备注: 由函数 Crea

16、teMutex 返回的句柄有 MUTEX_ALL_ACCESS 权限可以去访问新的互斥对象,并且可用在请求 互斥对象句柄的任何函数中。 调用进程中的任何线程可以在调用等待函数时指定互斥对象句柄。当指定对象的状态为信号态时。返回单 对象等待函数。当任何一个或者所有的互斥对象都为信号态时,返回多对象等待函数指令。等待函数返回后, 等待的线程被释放,继续向下执行。 当一个互斥对象不被任何线程拥有时,处于信号态。创建该对象的线程可以使用 bInitialOwner 标志来请求 立即获得对该互斥对象的所有权。否则,线程必须使用等待函数来请求所有权。当互斥对象处于信号态,等待 的线程获得对该对象的所有权时

17、,此互斥对象的状态被设置为非信号态,等待函数返回。任意时刻,仅有一个 线程能拥有该互斥对象线程可以使用 ReleaseMutex 函数来释放对这个互斥对象的所有权。 总线程已经拥有了个互斥对象,那么它可以重复调用等待函数而不会发生阻塞,一般情况下,用户不会 重复等待同一个互斥对象,这种机制防止了线程因等待它已经拥有的互斥对象而发生死锁。然而,线程必须为 每一次等待调用次 ReleaseMutex 函数来释放该互斥对象。 两个或多个进程可以调用 CreateMutex 来创建同名的互斥对象,第一个进程实际创建互斥对象以后的进 程打开已存在的互斥对象的句柄。这使得多个进程可以得到同一个互斥对象的句

18、柄,从而减轻了用户的负担, 使用户不必判断创建进程是否为第一个启动的进程。使用这种技术时,应该把 bInitialOwner 标志设为 FALSE ; 否则很难确定开始时哪一个进程拥有该互斥对象。 由于多进程能够拥有相同互斥对象的句柄,通过使用这个对象,可使多进程同步。以下为共享对象机制: 如果CreateMutex中的IpMutexAttributes 参数允许继承,由 CreateProcess函数创建的子进程可以继承父 近程的互斥对象句柄。 一个进程可以在调用 DupIicateHandIe 函数时指定互斥对象句柄来创建一个可以被其他进程使用的双重句 柄。一个进程在调用 OpenMute

19、x 或 CreateMutex 函数时能指定互斥对象名。 使用 CIoseHandIe 函数关闭句柄,进程结束时系统自动关闭句柄。当最后一个句柄被关闭时,互斥对象 被销毁。 5. ReleaseMutex 函数功能: 该函数放弃指定互斥对象的所有权。 函数原型: BOOL ReIeaseMutex (HANDLE hMutex ); 参数: hMutex :互斥对象句柄。为 CreateMutex 或 OpenMutex 函数的返回值。 返回值: 如果函数调用成功,那么返回值是非零值;如果函数调用失败,那么返回值是零值。若想获得更多错误信 息,请调用 GetLastError 函数。 备注:

20、如果调用线程不拥有互斥对象, ReIeaseMutex 函数失败。 一个线程通过调用等待函数拥有互斥对象。创建该互斥对象的线程也拥有互斥对象。而不需要调用等待函 数。当互斥对象的所有者线程不再需要互斥对象时,它可以调用ReIeaseMutex 函数。 当个线程拥有个互斥对象后,它可以用该互斥对象多次调用等待函数而不会阻塞。这防止一个线程等 待一个它已拥有的互斥对象时出现死锁。不过,为了释放所有权,该线程必须为每一个等待操作调用一次 ReIeaseMutex 函数; 6. WaitForSingleObject 函数功能: 当下列情况之一发生时该函数返回:(1)指定对象处于信号态;( 2)超时。

21、 函数原型: DWORD WaitForSingIeObject (HANDLE hHandIe, DWORD dwMiIIiseconds) 。 参数: hHandle :等待对象句柄。若想了解指定句柄的对象类型列表,参阅下面备注部分。 在 WindowsNT 中,句柄必须有 SYNCHRONIZE 访问权限。若想获得更多的信息,请查看 Standard Access Rights 。 dwMilliseconds: 指定以毫秒为单位的超时间隔。如果超时,即使对象的状态是非信号态的并且没有完 成,函数也返回。如果 dwMillseconds 是 0,函数测试对象的状态并立刻返回;如果 dwM

22、illseconds 是 INFINITE ,函数从不超时。 返回值: 如果函数调用成功,返回值表明引起函数返回的事件。可能值如下: WAIT_ABANDONED :指定对象是互斥对象,在线程被终止前,线程没有释放互斥对象。互斥对象的所属 关系被授予调用线程,并且该互斥对象被置为非信号态。 WAIT_OBJECT_0 :指定对象的状态被置为信号态。 WAIT_TIMEOUT :超时,并且对象的状态为非信号态。 如果函数调用失败,返回值是 WAIT_FAILED 。若想获得更多错误信息,请调用 GetLastError 函数。 备注: WaitForSingleObjects 函数决定等待条件是

23、否被满足。如果等待条件并没有被满足,调用线程进入个高效 的等待状态,当等待满足条件时占用非常少的处理器时间。 在运行前。一个等待函数修改同步对象类型的状态。修改仅发生在引起函数返回的对象身上。例如,信号 得计数减 1。 WaitForSingleObjects 函数能等待的对象包括:Change notification( 改变通告 ): Console input( 控制台输入 ); Event(事件);Job(作业);Mutex(互斥对象);Process进程);Semaphore(信号量);Thread(线程);Waitable timer (可等待定时器 )。 当使用等待函数或代码直接

24、或间接创建窗口时,一定要小心。如果一个线程创建了任何窗口,它必须处理 进程消息。消息广播被发送到系统的所有窗口。一个线程用没有超时的等待函数也许会引起系统死锁。间接创 建窗口的两个例子是 DDE 和 COM CoInitialize 。因此,如果用户有一个创建窗口的线程,用 MsgWaitForMultipleObjects 或 MsgWaitForMultipleObjectEx 函数,而不要用 SignalObjectAndWait 函数。 7. WaitForMultipleObjects 函数功能: WaitForMultipleObjects 函数当下列条件之一满足时返回:(1)任意

25、一个或全部指定对象处于信号态;(2) 超时间隔已过。 函数原型: DWORD WaitForMultipleObjects (DWORD nCount, CONST HANDLE *lpHandles, BOOL fWaitAll, DWORD dwMilliseconds)。 参数: nCount: 指定由 lpHandles 所指向的数组中的句柄对象数目最大对象句柄数目 MAXIMUM_W AIT_OBJECTS 。 lpHandles: 指向对象句柄数组的指针。该数组可以包含不同类型对象的句柄。在WindowsNT 中,该句 柄必须有 SYNCHRONIZE 访问权限。若想获得更多的信息

26、,请查看Standard Access Rights。 fWaitAll : 指定等待类型。如果为 TRUE ,当 lpHandles 指向的数组里的全部对象为信号态时,函数返 回。如果为 FALSE ,当由 lpHandles 指向的数组里的任对象为信号态时,函数返回。对于后者,返回值指出 引起函数返回的对象。 dwMilliseconds: 指定以毫秒为单位的超时间隔。如果超时,即使 bWaitAll 参数指定的条件没有满足, 函数也返回。如果 dwMilliseconds 是 0,函数测试指定对象的状态并立刻返回。如果 dwMilliseconds 是 INFINITE ,函数从不超时。

27、 返回值; 如果函数调用成功,返回值表明引起函数返回的事件。可能值如下: WAIT_OBJECT_0到 WAIT_OB JECT0+ nCount-1 :如果bWaitAII为TRUE,那么返回值表明所有指定对象 的状态为信号态。如果 bWaitAll 为 FALSE ,那么返回值减去 WAIT_OBJECT_0 表明引起函数返回的对象的 pHandles 数组索引。如果多于一个对象变为信号态,则返回的是数组索引最小的信号态对象索引。 WAIT_ABANDONED_0 到 WAIT_ABANDONED_0+nCount-1 :如果 bWaitAll 为 TRUE ,那么返回值表明所 有指定对象

28、的状态为信号态,并且至少一个对象是己放弃的互斥对象。如果 bWaitAll 为 FALSE ,那么返回值减 去 WAIT_ABANDONED_0 表明引起函数返回的放弃互斥对象的 pHandles 数组索引。 WAIT_TIMEOUT :超时并且由参数 bWaitAll 指定的条件没有满足。 如果函数调用失败,返回值是 WAIT_FAILED 。若想获得更多错误信息,请调用GetLastError 函数。 8. CreateSemapore 函数功能: 该函数是创建一个有名或者无名信号对象。 函数原型: HANDLE CreatSemaphore(LPSECURITY_ATTRIBUTES l

29、pAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName)。 参数; LpAttributes :安全属性。如果是 NULL就表示要使用默认属性。 IlnitialCount : Semaphore的初值。必须大于或等于0,并且小于或等于 MaxmumCount。 IMaximumCount : Semaphore的最大值。这也就是在同一时间内能够锁住Semaphore之线程的最多个 数。 IpName: Semaphore的名称(一个字符串)。任何线程(或进程)都可以根据这一名称引用到这个 Semaphore。这个

30、值可以是 NULL,意思是产生一个没有名字的Semaphore。 返回值: 如果成功就传回一个 handle,否则传回NULL。不论哪一种情况,GetLastError都会传回一个合理的结果。 如果指定的Semaphore名称已经存在,则该函数还是成功的,GetLastError会传回 ERROR_ALREADY_EXISTS 。 9. ReIeaseSemaphore 函数功能: 该函数将指定信号对象的计数增加一个指定的数量。 函数原型: BOOL ReleaseSemaphore (HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPrevio

31、usCount) 。 参数: hSemaphore: Semaphore 的 han die。 IReleaseCount: Semaphore现值的增额。该值不可以是负值或0。 IpPreviousCount:借此返回 Semaphore原来的值。 返回值: 如果成功,则返回 TRUE。否则返回FALSE。失败时可调用 GetLastError获得原因。 无论ReleaseSemaphore对于Semaphore所造成的当前值怎样增加,都绝对不会超过CreateSemaphore时所指 定的 1MaximumCount 。 请记住,IpPreviousCount所传回来的是一个瞬间值。你不可

32、以把IReleaseCount加上ipPreviousCount,就当 做是semaphore的当前值,因为其他线程可能已经改变了Semaphore的值。 与mutex不同的是,调用 ReleaseSemaphore的那个线程,并不一定就是调用WaitXxx的那个线程。仟何线 程都可以在任何时间调用ReieaseSemaphore解除被任何线程锁定的Semaphore。 10.lnitiaIizeCriticaISection 函数功能: 该函数初始化临界区对象: 函数原型: VOID InitializeCriticalSection (LPCRITIAL_SECTION lpCritica

33、lSection) 。 参数: IpCritialSection :指向临界区对象的指针。 备注: 单进程的所有线程可以使用互斥同步机制的临界区对象。但是,不能保证线程获得临界区所有权的顺序, 系统将对所有线程公平处理。 进程负责分配临界区对象使用的存储空间,这可以通过声明CRITICAL_SECTION 类型的变量来完成。在 使用临界区之前,该进程的一些线程必须使用 InitializeCriticalSection 或 InitializeCriticalSectionAndSpinCount 函 数来初始化该临界区对象。 11.EnterCriticalSection 函数功能: 函数原

34、型: 该函数是等待指定临界区对象的所有权。当调用线程被赋予所有权时,该函数返回。 VOID EnterCriticalSection (LPCRITICAL_SECTION lpCriticalSecrion) 参数: lpCriticalSecrion : 指间临界区对象的指针。 12.LeaveCriticalSection 函数功能: 该函数释放指定临界区对象的所有权。 函数原型: VOID LeaveCriticalSection (LPCRITICAL_SECTION lpCriticalSection) 。 参数; lpCriticalSecrion : 指向临界区对象的指针。 五

35、、参考源代码 下面的程序已经在 Windows 2000上实现。用 VC6.0创建源文件,将输入文件命名为thread.dat并放在与源 文件相同的文件夹内,编译运行即可。 #includewindows.h #include #include #include #include #include #include /读者 /写者 /每秒时钟中断数目 /最大线程数目 /最大数据文件数目 /字符串长度 /读者数目 /写者数目 #define READER R #define WRITER W #define INTE_PER_SEC 1000 #define MAX_THREAD_NUM 64

36、#define MAX_FILE_NUM 32 #define MAX_STR_LEN 32 int readcount=0 。 int writecount=0 。 CRITICAL_SECTION RP_Write 。/临界区 CRITICAL_SECTION cs_Write 。 CRITICAL_SECTION cs_Read 。 struct ThreadInfo int serial 。 char entity 。 double delay 。 double persist。 /线程序号 /线程类别(判断是读者线程还是写者线程) /线程延迟 /线程写操作持续时间 。 / /读者优先

37、读者线程 p:读者线程信息 void RP_ReaderThread(void *p) /互斥变量 HANDLE h_Mutex 。 h_Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,mutex_for_redcount) DWORD wait_for_mutex 。 /等待互斥变量所有权 DWORD m_delay 。/延迟时间 DWORD m_persist 。/读文件持续时间 int m_serial 。/线程序号 /从参数中获得信息 m_serial=(ThreadInfo*)(p)-serial 。 m_delay=(DWORD)(ThreadInfo

38、*)(p)-delay*INTE_PER_SEC) 。 m_persist=(DWORD)(ThreadInfo*)(p)-persist*INTE_PER_SEC) 。 Sleep(m_delay) 。 /延迟等待 printf(Reader thread %d sents the reading require.n,m_serial) 。 /等待互斥信号,保证对 readcount 的访问、修改互斥 wait_for_mutex=WaitForSingleObject(h_Mutex,-1) 。 /读者数目增加 readcount+ 。 if(readcount=1) /第一个读者,等待资

39、源 EnterCriticalSection(&RP_Write) 。 ReleaseMutex(h_Mutex) 。/释放互斥信号 /读文件 printf(Reader thread %d begins to read file.n,m_serial) 。 Sleep(m_persist) 。 /退出线程printf(Reader thread %d finished reading file.n,m_serial) 。 /等待互斥信号,保证对 readcount 的访问、修改互斥 wait_for_mutex=WaitForSingleObject(h_Mutex,-1) 。 /读者数目减

40、少 readcount-。 if(readcount=0) /如果所有的者读完,唤醒写者 LeaveCriticalSection(&Rp_Write) 。 /释放互斥信号 /延迟时间 /写文件持续时间 /线程序号 ReleaseMutex(h_Mutex) 。 / /读者优先写者线程 p:写者线程信息 void RP_WriterThread(void*p) DWORD m_delay 。 DWORD m_persist 。 int m_serial 。 /从参数中获得信息 m_serial=(ThreadInfo*)(p)-serial 。 m_delay=(DWORD)(ThreadIn

41、fo*)(p)-delay*INTE_pER_SEC) 。 m_persist=(DWORD)(ThreadInfo*)(p)-persist*INTE_pER_SEC) 。 Sleep(m_delay) 。/延迟等待 printf(Writer thread %d sent the wrinting require.n,m_serial) 。 /等待资源 EnterCriticalSection(&Rp_Write) 。 /写文件 printf(Writer thread %d begins to write to the file.n,m_serial) 。 Sleep(m_persist

42、) 。 /退出线程 printf(Writer thread %d finishing writing to the file.n,m_serial) /释放资源 LeaveCriticalSection(&Rp_Write) 。 / /读者优先处理函数 /file :文件名 void ReaderPriority(char *file) DWORD n_thread=0 。 DWORD thread_ID 。 DWORD wait_for_all 。 /线程数目 /线程 ID /等待所有线程结束 /互斥对象 HANDLE h_Mutex 。 h_Mutex=CreateMutex(NULL,

43、FALSE,mutex_for_readcount) /线程对象的数组 HANDLE h_ThreadMAX_THREAD_NUM ThreadInfo thread_infoMAX_THREAD_NUM readcount=0。 InitializeCriticalSection(&RP_Write) 。 /初始化临界区 ifstream inFile 。 inFile.open(file) 。 printf(Reader Priority:nn) 。 while(inFile) /读入每一个读者、写者的信息 inFilethread_infon_thread.serial 。 inFile

44、thread_infon_thread.entity 。 inFilethread_infon_thread.delay 。 inFilethread_infon_thread+.persist 。 inFile.get() 。 /初始化 readcount /打开文件 for(int i=0。iserial 。 m_delay=(DWORD)(ThreadInfo*)(p)-delay *INTE_PER_SEC) m_persist=(DWORD)(ThreadInfo*)(p)-persist *INTE_PER_SEC) Sleep(m_delay) 。 / 延迟等待 printf(R

45、eader thread %d sents the reading require.n,m_serial) wait_for_mutex1=WaitForSingleObject(h_Mutex1,-1) 。 / 读者进去临界区 EnterCriticalSection(&cs_Read) 。 / 阻塞互斥对象 Mutex2, 保证对 readCount 的访问和修改互斥 wait_for_mutex2=WaitForSingleObject(h_Mutex2,-1) 。 / 修改读者的数目 readcount+ 。 if(readcount=1) / 如果是第 1 个读者 ,等待写者写完 E

46、nterCriticalSection(&cs_Write) 。 ReleaseMutex(h_Mutex2) 。 / 释放互斥信号 Mutex2 / 让其他读者进去临界区 LeaveCriticalSection(&cs_Read) 。 ReleaseMutex(h_Mutex1) 。 / 读文件 printf(Reader thread %d begins to read file.n,m_serial) Sleep(m_persist) 。 /退出线程 printf(Reader thread %d finished reading file.n,m_serial) 。 / 阻塞互斥对象

47、 Mutex2, 保证对 readcount 的访问 ,修改互斥 wait_for_mutex2=WaitForSingleObject(h_Mutex2,-1) 。 readcount- 。 if(readcount=0) / 最后一个读者 ,唤醒写者 LeaveCriticalSection(&cs_Write) 。 ReleaseMutex(h_Mutex2) 。 / 释放互斥信号 / /写者优先写者线程 p:写者线程信息 void WP_WriterThread(void*p) /请编写写者优先的写者线程 DWORD wait_for_mutex3 。 / 互斥变量 DWORD m_d

48、elay 。 / 延迟时间 DWORD m_persist 。 / 读文件持续时间 int m_serial 。 / 线程序号 HANDLE h_Mutex3 。 h_Mutex3=OpenMutex(MUTEX_ALL_ACCESS,FALSE,_T(mutex3) /从参数中获得信息 m_serial=(ThreadInfo*)(p)-serial 。 m_delay=(DWORD)(ThreadInfo*)(p)-delay *INTE_pER_SEC) m_persist=(DWORD)(ThreadInfo*)(p)-persist *INTE_pER_SEC) Sleep(m_de

49、lay) 。 / 延迟等待 printf(Writer thread %d sents the writing require.n,m_serial) wait_for_mutex3=WaitForSingleObject(h_Mutex3,-1) 。 writecount+ 。 / 修改写者数目 if(writecount=1) EnterCriticalSection(&cs_Read) 。 ReleaseMutex(h_Mutex3) 。 EnterCriticalSection(&cs_Write) 。 printf(Writer thread %d begins to write t

50、o the file.n,m_serial) Sleep(m_persist) 。 printf(Writer thread %d finished writing to the file.n,m_serial) LeaveCriticalSection(&cs_Write) 。 wait_for_mutex3=WaitForSingleObject(h_Mutex3,-1) 。 writecount- 。 if(writecount=0) LeaveCriticalSection(&cs_Read) 。 ReleaseMutex(h_Mutex3) 。 / /写者优先处理函数 /file :

51、文件名 void WriterPriority(char *file) /请编写写者优先处理函数 DWORD n_thread=0 。 DWORD thread_ID 。 DWORD wait_for_all 。 HANDLE h_Mutex1 。 h_Mutex1=CreateMutex(NULL,FALSE,_T(mutex1) HANDLE h_Mutex2 。 h_Mutex2=CreateMutex(NULL,FALSE,_T(mutex2) HANDLE h_Mutex3 。 h_Mutex3=CreateMutex(NULL,FALSE,_T(mutex3) HANDLE h_T

52、hreadMAX_THREAD_NUM 。 ThreadInfo thread_infoMAX_THREAD_NUM 。 readcount=0 。 writecount=0 。 InitializeCriticalSection(&cs_Write) 。 InitializeCriticalSection(&cs_Read) 。 ifstream inFile 。 inFile.open (file)printf(Writer priority:nn) 。 while(inFile) inFilethread_infon_thread.serial。 inFilethread_infon_t

53、hread.entity。 inFilethread_infon_thread.delay。 inFilethread_infon_thread+.persist 。 inFile.get() 。 for(int i=0 。 i0) 。 但是这种方式会让主函数循环等待,浪费了 CPU 资源。 相比之下,考虑到运行效率,还是实例中给出的方法比较好些。 六、示例程序的结果分析 对数据文件 thread.dat 进行分析: 1 R 3 5 2 W 4 5 3 R 5 2 4 R 6 5 5 W 5.1 3 读者优先结果: Reader Priority: Reader thread 1 sents the reading require. Reader thread 1 begins to read file. Writer thread 2 sent

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论