操作系统课程设计读者写者问题.docx

上传人:b****7 文档编号:16390881 上传时间:2023-07-13 格式:DOCX 页数:30 大小:26.56KB
下载 相关 举报
操作系统课程设计读者写者问题.docx_第1页
第1页 / 共30页
操作系统课程设计读者写者问题.docx_第2页
第2页 / 共30页
操作系统课程设计读者写者问题.docx_第3页
第3页 / 共30页
操作系统课程设计读者写者问题.docx_第4页
第4页 / 共30页
操作系统课程设计读者写者问题.docx_第5页
第5页 / 共30页
操作系统课程设计读者写者问题.docx_第6页
第6页 / 共30页
操作系统课程设计读者写者问题.docx_第7页
第7页 / 共30页
操作系统课程设计读者写者问题.docx_第8页
第8页 / 共30页
操作系统课程设计读者写者问题.docx_第9页
第9页 / 共30页
操作系统课程设计读者写者问题.docx_第10页
第10页 / 共30页
操作系统课程设计读者写者问题.docx_第11页
第11页 / 共30页
操作系统课程设计读者写者问题.docx_第12页
第12页 / 共30页
操作系统课程设计读者写者问题.docx_第13页
第13页 / 共30页
操作系统课程设计读者写者问题.docx_第14页
第14页 / 共30页
操作系统课程设计读者写者问题.docx_第15页
第15页 / 共30页
操作系统课程设计读者写者问题.docx_第16页
第16页 / 共30页
操作系统课程设计读者写者问题.docx_第17页
第17页 / 共30页
操作系统课程设计读者写者问题.docx_第18页
第18页 / 共30页
操作系统课程设计读者写者问题.docx_第19页
第19页 / 共30页
操作系统课程设计读者写者问题.docx_第20页
第20页 / 共30页
亲,该文档总共30页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

操作系统课程设计读者写者问题.docx

《操作系统课程设计读者写者问题.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计读者写者问题.docx(30页珍藏版)》请在冰点文库上搜索。

操作系统课程设计读者写者问题.docx

操作系统课程设计读者写者问题

操作系统课程设计——读者写者问题

一、实习要求

在windows2000环境下,创建一个控制台进程,此进程包含n个线程。

用这n个线程来表示n个读者或写者。

每个线程按相应测试数据文件(后面有介绍)的要求进行读写操作。

用信号量机制分别实现读者优先和写者优先的读者—写者问题。

读者—写者问题的读写操作限制(包括读者优先和写者优先):

1)写—写互斥,即不能有两个写者同时进行写操作。

2)读—写互斥,即不能同时有一个线程在读,而另一个线程在写。

3)读—读允许,即可以有一个或多个读者在读。

读者优先的附加限制:

如果一个读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。

写者优先的附加限制:

如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。

运行结果显示要求:

要求在每个线程创建、发出读写操作申请、开始读写操作和结束读写操作时分别显示一行提示信息,以确定所有处理都遵守相应的读写操作限制。

二、测试数据文件格式

测试数据文件包括n行测试数据,分别描述创建的n个线程是读者还是写者,以与读写操作的开始时间和持续时间。

每行测试数据包括四个字段,各个字段间用空格分隔。

第—字段为—个正整数,表示线程序号。

第二字段表示相应线程角色,R表示读者,W表示写者。

第三字段为一个正数,表示读写操作的开始时间:

线程创建后,延迟相应时间(单位为秒)后发出对共享资源的读写申请。

第四字段为一个正数,表示读写操作的持续时间。

当线程读写申请成功后,开始对共享资源的读写操作,该操作持续相应时间后结束,并释放共享资源。

下面是—个测试数据文件的例子:

1R35

2W45

3R52

4R65

5W5.13

注意在创建数据文件时,由于涉与到文件格式问题,最好在记事本中手工逐个键入数据,而不要拷贝粘贴数据,否则,本示例程序运行时可能会出现不可预知的错误。

三、实习分析

可以将所有读者和所有写者分别存于一个读者等待队列和一个写者等待队列中,每当读允许时,就从读者队列中释放一个或多个读者线程进行读操作;每当写允许时,就从写者队列中释放一个写者进行写操作。

1.读者优先

读者优先指的是除非有写者在写文件,否则读者不需要等待。

所以可以用—个整型变量readcount记录当前的读者数目,用于确定是否需要释放正在等待的写者线程(当readcount=0时,表明所有的读者读完,需要释放写者等待队列中的一个写者)。

每一个读者开始读文件时,必须修改readcount变量。

因此需要一个互斥对象mutex来实现对全局变量readcount修改时的互斥。

另外,为了实现写—写互斥,需要增加一个临界区对象RP_Write。

当写者发出写请求时,必须申请临界区对象的所有权。

通过这种方法,也可以实现读—写互斥、当readcount=1时(即第一个读者到来时),读者线程也必须申请临界区对象的所有权。

当读者拥有临界区的所有权时,写者阻塞在临界区对象RP_Write上。

当写者拥有临界区的所有权时,第一个读者判断完“readcount==1”后阻塞在write上,其余的读者由于等待对readcount的判断,阻塞在mutex上。

2.写者优先(请根据自己编写的写者优先程序进行分析)

四、相关API函数说明

1.CreateThread

函数功能:

该函数创建一个在调用进程的地址空间中执行的线程。

函数原型:

HANDLECreateThread(LPSECURITY_ATTRIBUTESlpThreadAttributes,

DWORDdwStackSize,LPTHREAD_START_ROUTINElpStartAddress,

LPVOIDlpParameter,DWORDdwCreationFlags,LPDWORDlpThreadId);

参数:

·lpThreadAttributes:

指向一个LPSECURITY_ATTRIBUTES结构。

该结构决定了返回的句柄是否可被子进程继承。

若lpThreadAttributes为NULL,则句柄不能被继承。

在WindowsNT中该结构的lpSecurityDescriptor成员定义了新进程的安全性描述符。

若lpThreadAttributes为NULL。

则线程获得—个默认的安全性描述符。

·dwStackSize:

定义原始堆栈提交时的大小(按字节计)。

系统将该值舍入为最近的页。

若该值为0,或小于默认时提交的大小,默认情况是使用与调用线程同样的大小.更多的信息,请看ThreadStackSize。

·lpStartAddress:

指向一个LPTHREAD_START_ROUTINE类型的应用定义的函数,该线程执行此函数。

该指针还表示远程进程中线程的起始地址。

该函数必须存在于远程进程中。

·lpParameter:

定义一个传递给该进程的32位值。

·dwCreationFlags:

定义控制进程创建的附加标志。

若定义了CREATE_SUSPENDED标志,线程创建时处于挂起状态,并且直到ResumeThread函数调用时才能运行。

若该值为0,则该线程在创建后立即执行。

·lpThreadId:

指向—个32位值,它接收该线程的标识符。

返回值:

若函数调用成功,返回值为新线程的句柄;若函数调用失败,返回值为NULL。

备注:

新进程的句柄创建时设为THREAD_ALL_ACCESS访问权限。

若未提供安全性描述符,则该句柄可被任何要求一个线程对象句柄的函数所使用。

若提供了安全性描述符,则以后使用该句柄时,将在授权访问以前执行访问检查。

若访问检查拒绝访问,则请求进程不能使用该句柄获得对该线程的访问。

线程从lpStartAddress参数定义的函数处开始执行。

若该函数返回,系统将默认地认为以调用ExitThread函数的方法终止该线程。

使用GetExitcodeThread函数来获得线程的返回值。

线程创建时拥有THREAD_PRIORITY_NORMAL优先权。

使用GetThreadPriority和SetThreadPriority函数可以获得和设置线程的优先权值。

一个线程终止时。

该线程对象被设为发信号状态,以满足在该对象上等待的所有进程。

一个线程对象始终存在于系统中,直到该线程终止,且它所有的句柄都已通过调用CloseHandle函数关闭。

2.ExitThread

函数功能:

该函数结束一个线程。

函数原型:

VOIDExitThread(DWORDdwExitCode);

参数:

·dwExitCode:

定义调用线程的退出代码。

使用GetExitCodeThread函数来检测一个线程的退出代码。

返回值:

无。

备注:

调用ExitThread函数,是结束—个线程的较好的方法。

调用该函数后(或者直接地调用,或者从一个线程过程返回),当前线程的堆栈取消分配,线程终止。

若调用该函数时,该线程为进程的最后一个线程,则该线程的进程也被终止。

线程对象的状态变为发信号状态,以释放所有正在等待该线程终止的其他线程。

线程的终止状态从STILL_ACTIVATE变为dwExitCode参数的值。

线程结束时不必从操作系统中移去该线程对象。

当线程的最后一个句柄关闭时,该线程对象被删除。

3.Sleep

函数功能:

该函数对于指定的时间间隔挂起当能的执行线程。

函数原型:

VOIDSleep(DWORDdwMulliseconds);

参数:

·dwMilliseconds:

定义挂起执行线程的时间,以毫秒(ms)为单位。

取值为0时,该线程将余下的时间片交给处于就绪状态的同一优先级的其他线程。

若没有处于就绪状态的同一优先级的其他线程,则函数立即返回,该线程继续执行。

若取值为INFINITE则造成无限延迟。

返回值:

该函数没有返回值。

备注:

一个线程可以在调用该函数时将睡眠时间设为0ms,以将剩余的时间片交出。

4.CreateMutex

函数功能:

该函数创建有名或者无名的互斥对象。

函数原型:

HANDLECreateMutex(LPSECURITY_ATTRIBUTESlpMutexAttributes,

BOOLbInitialOwner,LPCTSTRlpName);

参数:

·lpMutexAttributes:

指向SECURITY_ATTRIBUTES结构的指针,该结构决定子进程是否能继承返回句柄。

如果lpMutexAttributes为NULL,那么句柄不能被继承。

在WindowsNT中该结构的LpSecuriyDescriptor成员指定新互斥对象的安全描述符。

如果lpMutexAttributes为NULL,那么互斥对象获得默认的安全描述符。

·bInitialOwner:

指定互斥对象的初始所属身份。

如果该值为TRUE,并且调用者创建互斥对象,那么调用线程获得互斥对象所属身份。

否则,调用线程不能获得互斥对象所属身份。

判断调用者是否创建互斥对象清参阅返回值部分。

·lpName:

指向以NULL结尾的字符串,该字符串指定了互斥对象名。

该名字的长度小于MAX_PATH且可以包含除反斜线(\)路径分隔符以外的任何字符。

名字是区分大小写的。

如果lpName与已存在的有名互斥对象名相匹配,那么该函数要求用MUTEX_ALL_ACCESS权限访问已存在的对象。

在这种情况下,由于参数bInitialOwner已被创建进程所设置,该参数被忽略。

如果参数lpMutexAttributes不为NULL,它决定句柄是否解除继承,但是其安全描述符成员被忽略。

如果lpName为NULL,那么创建的互斥对象无名。

如果lpName与已存在的事件、信号量、可等待定时器、作业或者义件映射对象的名字相匹配,那么函数调用失败,并且GetLastError函数返回ERROR_ALREADY_HANDLE,其原因是这些对象共享一样的名字空间。

返回值:

如果函数调用成功,返回值是互斥对象句柄;如果函数调用之前,有名互斥对象已存在,那么函数给已存在的对象返回一个句柄,并且函数GetLastError返回ERROR_ALREADY_EXISTS。

否则,调用者创建互斥对象。

如果函数调用失败,则返回值为NULL。

若想获得更多错误信息,请调用GetLastError函数。

备注:

由函数CreateMutex返回的句柄有MUTEX_ALL_ACCESS权限可以去访问新的互斥对象,并且可用在请求互斥对象句柄的任何函数中。

调用进程中的任何线程可以在调用等待函数时指定互斥对象句柄。

当指定对象的状态为信号态时。

返回单对象等待函数。

当任何一个或者所有的互斥对象都为信号态时,返回多对象等待函数指令。

等待函数返回后,等待的线程被释放,继续向下执行。

当一个互斥对象不被任何线程拥有时,处于信号态。

创建该对象的线程可以使用bInitialOwner标志来请求立即获得对该互斥对象的所有权。

否则,线程必须使用等待函数来请求所有权。

当互斥对象处于信号态,等待的线程获得对该对象的所有权时,此互斥对象的状态被设置为非信号态,等待函数返回。

任意时刻,仅有一个线程能拥有该互斥对象.线程可以使用ReleaseMutex函数来释放对这个互斥对象的所有权。

总线程已经拥有了—个互斥对象,那么它可以重复调用等待函数而不会发生阻塞,一般情况下,用户不会重复等待同一个互斥对象,这种机制防止了线程因等待它已经拥有的互斥对象而发生死锁。

然而,线程必须为每一次等待调用—次ReleaseMutex函数来释放该互斥对象。

两个或多个进程可以调用CreateMutex来创建同名的互斥对象,第一个进程实际创建互斥对象.以后的进程打开已存在的互斥对象的句柄。

这使得多个进程可以得到同一个互斥对象的句柄,从而减轻了用户的负担,使用户不必判断创建进程是否为第一个启动的进程。

使用这种技术时,应该把bInitialOwner标志设为FALSE;否则很难确定开始时哪一个进程拥有该互斥对象。

由于多进程能够拥有一样互斥对象的句柄,通过使用这个对象,可使多进程同步。

以下为共享对象机制:

·如果CreateMutex中的lpMutexAttributes参数允许继承,由CreateProcess函数创建的子进程可以继承父近程的互斥对象句柄。

·一个进程可以在调用DuplicateHandle函数时指定互斥对象句柄来创建一个可以被其他进程使用的双重句柄。

一个进程在调用OpenMutex或CreateMutex函数时能指定互斥对象名。

·使用CloseHandle函数关闭句柄,进程结束时系统自动关闭句柄。

当最后一个句柄被关闭时,互斥对象被销毁。

5.ReleaseMutex

函数功能:

该函数放弃指定互斥对象的所有权。

函数原型:

BOOLReleaseMutex(HANDLEhMutex);

参数:

·hMutex:

互斥对象句柄。

为CreateMutex或OpenMutex函数的返回值。

返回值:

如果函数调用成功,那么返回值是非零值;如果函数调用失败,那么返回值是零值。

若想获得更多错误信息,请调用GetLastError函数。

备注:

如果调用线程不拥有互斥对象,ReleaseMutex函数失败。

一个线程通过调用等待函数拥有互斥对象。

创建该互斥对象的线程也拥有互斥对象。

而不需要调用等待函数。

当互斥对象的所有者线程不再需要互斥对象时,它可以调用ReleaseMutex函数。

当—个线程拥有—个互斥对象后,它可以用该互斥对象多次调用等待函数而不会阻塞。

这防止一个线程等待一个它已拥有的互斥对象时出现死锁。

不过,为了释放所有权,该线程必须为每一个等待操作调用一次ReleaseMutex函数;

6.WaitForSingleObject

函数功能:

当下列情况之一发生时该函数返回:

(1)指定对象处于信号态;

(2)超时。

函数原型:

DWORDWaitForSingleObject(HANDLEhHandle,DWORDdwMilliseconds);

参数:

·hHandle:

等待对象句柄。

若想了解指定句柄的对象类型列表,参阅下面备注部分。

在WindowsNT中,句柄必须有SYNCHRONIZE访问权限。

若想获得更多的信息,请查看StandardAccessRights。

·dwMilliseconds:

指定以毫秒为单位的超时间隔。

如果超时,即使对象的状态是非信号态的并且没有完成,函数也返回。

如果dwMillseconds是0,函数测试对象的状态并立刻返回;如果dwMillseconds是INFINITE,函数从不超时。

返回值:

如果函数调用成功,返回值表明引起函数返回的事件。

可能值如下:

WAIT_ABANDONED:

指定对象是互斥对象,在线程被终止前,线程没有释放互斥对象。

互斥对象的所属关系被授予调用线程,并且该互斥对象被置为非信号态。

WAIT_OBJECT_0:

指定对象的状态被置为信号态。

WAIT_TIMEOUT:

超时,并且对象的状态为非信号态。

如果函数调用失败,返回值是WAIT_FAILED。

若想获得更多错误信息,请调用GetLastError函数。

备注:

WaitForSingleObjects函数决定等待条件是否被满足。

如果等待条件并没有被满足,调用线程进入—个高效的等待状态,当等待满足条件时占用非常少的处理器时间。

在运行前。

一个等待函数修改同步对象类型的状态。

修改仅发生在引起函数返回的对象身上。

例如,信号得计数减1。

WaitForSingleObjects函数能等待的对象包括:

Changenotification(改变通告):

Consoleinput(控制台输入);Event(事件);Job(作业);Mutex(互斥对象);Process(进程);Semaphore(信号量);Thread(线程);Waitabletimer(可等待定时器)。

当使用等待函数或代码直接或间接创建窗口时,一定要小心。

如果一个线程创建了任何窗口,它必须处理进程消息。

消息广播被发送到系统的所有窗口。

一个线程用没有超时的等待函数也许会引起系统死锁。

间接创建窗口的两个例子是DDE和COMCoInitialize。

因此,如果用户有一个创建窗口的线程,用MsgWaitForMultipleObjects或MsgWaitForMultipleObjectEx函数,而不要用SignalObjectAndWait函数。

7.WaitForMultipleObjects

函数功能:

WaitForMultipleObjects函数当下列条件之一满足时返回:

(1)任意一个或全部指定对象处于信号态;

(2)超时间隔已过。

函数原型:

DWORDWaitForMultipleObjects(DWORDnCount,CONSTHANDLE*lpHandles,

BOOLfWaitAll,DWORDdwMilliseconds);

参数:

·nCount:

指定由lpHandles所指向的数组中的句柄对象数目最大对象句柄数目MAXIMUM_WAIT_OBJECTS。

·lpHandles:

指向对象句柄数组的指针。

该数组可以包含不同类型对象的句柄。

在WindowsNT中,该句柄必须有SYNCHRONIZE访问权限。

若想获得更多的信息,请查看StandardAccessRights。

·fWaitAll:

指定等待类型。

如果为TRUE,当lpHandles指向的数组里的全部对象为信号态时,函数返回。

如果为FALSE,当由lpHandles指向的数组里的任—对象为信号态时,函数返回。

对于后者,返回值指出引起函数返回的对象。

·dwMilliseconds:

指定以毫秒为单位的超时间隔。

如果超时,即使bWaitAll参数指定的条件没有满足,函数也返回。

如果dwMilliseconds是0,函数测试指定对象的状态并立刻返回。

如果dwMilliseconds是INFINITE,函数从不超时。

返回值;

如果函数调用成功,返回值表明引起函数返回的事件。

可能值如下:

WAIT_OBJECT_0到WAIT_OBJECT0+nCount-1:

如果bWaitAll为TRUE,那么返回值表明所有指定对象的状态为信号态。

如果bWaitAll为FALSE,那么返回值减去WAIT_OBJECT_0表明引起函数返回的对象的pHandles数组索引。

如果多于一个对象变为信号态,则返回的是数组索引最小的信号态对象索引。

WAIT_ABANDONED_0到WAIT_ABANDONED_0+nCount-1:

如果bWaitAll为TRUE,那么返回值表明所有指定对象的状态为信号态,并且至少一个对象是己放弃的互斥对象。

如果bWaitAll为FALSE,那么返回值减去WAIT_ABANDONED_0表明引起函数返回的放弃互斥对象的pHandles数组索引。

WAIT_TIMEOUT:

超时并且由参数bWaitAll指定的条件没有满足。

如果函数调用失败,返回值是WAIT_FAILED。

若想获得更多错误信息,请调用GetLastError函数。

8.CreateSemapore

函数功能:

该函数是创建一个有名或者无名信号对象。

函数原型:

HANDLECreatSemaphore(LPSECURITY_ATTRIBUTESlpAttributes,

LONGlInitialCount,LONGlMaximumCount,LPCTSTRlpName);

参数;

·LpAttributes:

安全属性。

如果是NULL就表示要使用默认属性。

·lInitialCount:

Semaphore的初值。

必须大于或等于0,并且小于或等于MaxmumCount。

·lMaximumCount:

Semaphore的最大值。

这也就是在同一时间能够锁住Semaphore之线程的最多个数。

·lpName:

Semaphore的名称(一个字符串)。

任何线程(或进程)都可以根据这一名称引用到这个Semaphore。

这个值可以是NULL,意思是产生—个没有名字的Semaphore。

返回值:

如果成功就传回一个handle,否则传回NULL。

不论哪一种情况,GetLastError都会传回一个合理的结果。

如果指定的Semaphore名称已经存在,则该函数还是成功的,GetLastError会传回ERROR_ALREADY_EXISTS。

9.ReleaseSemaphore

函数功能:

该函数将指定信号对象的计数增加—个指定的数量。

函数原型:

BOOLReleaseSemaphore(HANDLEhSemaphore,LONGlReleaseCount,

LPLONGlpPreviousCount);

参数:

·hSemaphore:

Semaphore的handle。

·lReleaseCount:

Semaphore现值的增额。

该值不可以是负值或0。

·lpPreviousCount:

借此返回Semaphore原来的值。

返回值:

如果成功,则返回TRUE。

否则返回FALSE。

失败时可调用GetLastError获得原因。

无论ReleaseSemaphore对于Semaphore所造成的当前值怎样增加,都绝对不会超过CreateSemaphore时所指定的1MaximumCount。

请记住,lpPreviousCount所传回来的是一个瞬间值。

你不可以把1ReleaseCount加上lpPreviousCount,就当做是semaphore的当前值,因为其他线程可能已经改变了Semaphore的值。

与mutex不同的是,调用ReleaseSemaphore的那个线程,并不一定就是调用WaitXxx的那个线程。

仟何线程都可以在任何时间调用ReleaseSemaphore,解除被任何线程锁定的Semaphore。

10.InitializeCriticalSection

函数功能:

该函数初始化临界区对象:

函数原型:

VOIDInitializeCriticalSection(LPCRITIAL_SECTIONlpCriticalSection);

参数:

·lpCritialSection:

指向临界区对象的指针。

备注:

单进程的所有线程可以使用互斥同步机制的临界区对象。

但是,不能保证线程获得临界区所有权的顺序,系统将对所有线程公平处理。

进程负责分配临界区对象使用的存储空间,这可以通过声明CRITICAL_SECTION类型的变量来完成。

在使用临界区之前,该进程的一些线程必须使用InitializeCriticalSection或InitializeCriticalSectionAndSpinCount函数来初始化该临界区对象。

11.EnterCriticalSection

函数功能:

该函数是等待指定临界区对象的所有权。

当调用线程被赋予所有权时,该函数返回。

函数原型:

VOIDEnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSecrion);

参数:

·lpCriticalSecrion:

指间临界区对象的指针。

12.LeaveCriticalSection

函数功能:

该函数释放指定临界区对象的所有权。

函数原型:

VOIDLeaveCriticalSection(LPCRITICAL_SECTIONlpCritical

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

当前位置:首页 > 自然科学 > 物理

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2