logo资料库

操作系统读者写者问题.doc

第1页 / 共13页
第2页 / 共13页
第3页 / 共13页
第4页 / 共13页
第5页 / 共13页
第6页 / 共13页
第7页 / 共13页
第8页 / 共13页
资料共13页,剩余部分请下载后查看
一、实验题目
二、实验目的
三、实验条件和环境
四、实验原理
五、实验方法
六、实验结果及结论
附录:程序清单及说明
一、实验题目 读者写者问题 二、实验目的 1、通过编写和调试程序以加深对进程、线程管理方案的理解; 2、熟悉 Windows 多线程程序设计方法; 三、实验条件和环境 硬件设备:多台计算机。 系统软件:windows 操作系统,Visual C++6.0 编译环境。 四、实验原理 读者写者问题是一个用信号量实现的经典进程同步问题。在系统中,一个 数据集( 如文件或记录) 被几个并发进程共享,这些线程分两类,一部分只要求 进行复操作,称之为“读者”;另一类要求写或修改操作,我们称之为“写 者”。一般而言,对一个数据集,为了保证数据的完整性、正确性,允许多个 读者进程同时访问,但是不允许一个写者进程同其它任何一个进程(读者或者 写者)同时访问,而这类问题就称之为“读者写者”问题。 读者优先的算法在操作系统相关的书籍中都有介绍,这是一种最简单的解 决办法。当没有写进程正在访问共享数据集时,读进程可以进入访问,否则必 须等待。而读者优先的算法存在“饿死写者”线程的问题。只要有读者不断到 来,写者就要持久地等待,直到所有的读者都读完且没有新的读者到来时写者 才能写数据集。而在很多情况下我们需要避免“饿死写者”,故而采用写者优 先算法。 五、实验方法 在 Windows 环境下,创建一个控制台进程,此进程包含 n 个线程。用这 n 个线程来表示 n 个读者或写者。每个线程按相应测试数据文件(后面介绍)的 要求进行读写操作。用信号量机制分别实现读者优先和写者优先问题。 读者-写者问题的读写操作限制(包括读者优先和写者优先) 1)写-写互斥:不能有两个写者同时进行写操作 2)读-写互斥:不能同时有一个线程在读,而另一个线程在写。 3)读-读允许:可以有一个或多个读者在读。 读者优先的附加限制:如果读者申请进行读操作时已有另一个读者正在进 行读操作,则该读者可直接开始读操作。 写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等 待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操 作。 运行结果显示要求:要求在每个线程创建、发出读写申请、开始读写操作 和结束读写操作时分别显示一行提示信息,以确定所有处理都遵守相应的读写 操作限制。
1 测试数据文件包括 n 行测试数据,分别描述创建的 n 个线程是读者还是写 者,以及读写操作的开始时间和持续时间。每行测试数据包括四个字段,每个 字段间用空格分隔。第 1 个字段为正整数,表示线程的序号。第 2 个字段表示 线程的角色,R 表示读者,W 表示写者。第 3 个字段为一个正数,表示读写开 始时间:线程创建后,延迟相应时间(单位为秒)后发出对共享资源的读写申 请。第 4 个字段为一个正数,表示读写操作的延迟时间。当线程读写申请成功 后,开始对共享资源进行读写操作,该操作持续相应时间后结束,释放该资 源。 下面是一个测试数据文件的例子(在记事本手工录入数据): 1 R 3 5 2 W 4 5 3 R 5 2 4 R 6 5 5 W 5.1 3 六、实验结果及结论 1、读者优先 在读者写者同时在队列中等待申请资源时,读者优先调用资源。而且如果 一个读者申请进行读操作时已有另一读者正在进行读操作,则该读者可直接开 始读操作,即读读允许。 进程 1 是 R 操作,在时间 3 时进入队列,运行时间是 5,在它进入时没有 进程占用资源,它就占用资源;它释放资源时,等候的进程有 2 和 5; 进程 2 是 W 操作,在时间 4 时进入队列,运行时间是 5,在它进入时进程 1 占用资源,它等待资源,当 1 释放资源后,进程 4 在占用资源,它依然等待, 直到进程 4 结束; 进程 3 是 R 操作,在时间 5 时进入队列,运行时间是 2,在它进入时进程 1 占用资源,由于读读允许,它和进程 1 同时调用资源; 进程 4 是 R 操作,在时间 6 时进入队列,运行时间是 5,在它进入时进程 1 和 3 占用资源,由于读读允许,它和进程 1、3 同时调用资源; 进程 5 是 W 操作,在时间 5.1 时进入队列,运行时间是 3,在它进入时进 程 1 占用资源,它等待资源,当 1 释放资源后,进程 4 在占用资源,它依然等 待,当 4 释放资源后,进程 2 占用资源,由于写写互斥,它依然等待,直到进 程 2 结束。 2、写者优先 如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该 读者必须等到没有写者处于等待状态后才能开始读操作。 进程 1 是 R 操作,在时间 3 时进入队列,运行时间是 5,在它进入时没有 进程占用资源,它就占用资源;它释放资源时,等候的进程有 2、3、4、5; 进程 2 是 W 操作,在时间 4 时进入队列,运行时间是 5,在它进入时进程 1 占用资源,它等待资源,当 1 释放资源后,由于写者优先,它就占用资源, 它释放资源时,等候的进程有 3、4、5; 进程 3 是 R 操作,在时间 5 时进入队列,运行时间是 2,在它进入时进程 1 占用资源,由于写者优先,它等进程 2 和 5 都释放资源后才能调用资源; 进程 4 是 R 操作,在时间 6 时进入队列,运行时间是 5,与进程 3 相同;
进程 5 是 W 操作,在时间 5.1 时进入队列,运行时间是 3,在它进入时进 程 1 占用资源,它等待资源,当 1 释放资源后,进程 2 占用资源,由于写写互 斥,它依然等待,直到进程 2 结束。 2
3 图 1 读者优先结果图
4
图 2 写者优先结果图 5 附录:程序清单及说明 1、程序读者优先: #include #include #include #include #include #include #define MAX_PERSON 100 #define READER #define WRITER #define END #define R #define W -1 READER WRITER 0 1 typedef struct _Person { HANDLE m_hThread; int m_nType; int m_nStartTime; int m_nWorkTime; int m_nID; }Person; //最多 100 人 //读者 //写者 //结束 //定义处理线程的句柄 //进程类型(读写) //开始时间 //运行时间 //进程号 Person g_Persons[MAX_PERSON]; int g_NumPerson = 0; long g_CurrentTime= 0; //基本时间片数 int g_PersonLists[] = { //进程队列 1, R, 3, 5, 2, W, 4, 5, 3, R, 5, 2, 4, R, 6, 5, 5, W, 5.1, 3, END, }; int g_NumOfReading = 0; int g_NumOfWriteRequest = 0; HANDLE g_hReadSemaphore; HANDLE g_hWriteSemaphore; bool finished = false; //bool wfinished = false; //申请写进程的个数 //读者信号 //写者信号 //所有的读完成 //所有的写完成 void CreatePersonList(int *pPersonList); bool CreateReader(int StartTime,int WorkTime,int ID); bool CreateWriter(int StartTime,int WorkTime,int ID); DWORD WINAPI ReaderProc(LPVOID lpParam);
DWORD WINAPI WriterProc(LPVOID lpParam); 6 int main() { g_hReadSemaphore = CreateSemaphore(NULL,1,100,NULL); g_hWriteSemaphore = CreateSemaphore(NULL,1,100,NULL); //创建信号灯,当前可用的资源数为 1,最大为 100 //创建信号灯,当前可用的资源数为 1,最大为 100 CreatePersonList(g_PersonLists); printf("Created all the reader and writer\n...\n"); g_CurrentTime = 0; while(true) { // Create All the reader and writers Sleep(300); // 300 ms g_CurrentTime++; printf("----------------------------------------------------- \nCurrentTime = %d\n",g_CurrentTime); if(finished) { system("pause"); return 0; } } } void CreatePersonList(int *pPersonLists) { int i=0; int *pList = pPersonLists; bool Ret; while(pList[0] != END) { switch(pList[1]) { case R: Ret = CreateReader(pList[2],pList[3],pList[0]);//351,w452,523,654 break; case W: Ret = CreateWriter(pList[2],pList[3],pList[0]); break; } if(!Ret) } } printf("Create Person %d is wrong\n",pList[0]); pList += 4; // move to next person list DWORD WINAPI ReaderProc(LPVOID lpParam)//读过程 { Person *pPerson = (Person*)lpParam; // wait for the start time while(g_CurrentTime != pPerson->m_nStartTime) {
7 //读操作还没有到达执行时间,则等待 } printf("Reader %d is Requesting ...\n",pPerson->m_nID); //printf("\n\n************************************************\n"); // wait for the write request /* while(g_NumOfWriteRequest != 0) { //g_NumOfWriteRequest != 0 表示现在正在写,不能读 }*/ //该语句在写者优先的时候是认为写者优先级高于读者,在有写者的时候读者需//要等候, 而在读者优先的时候,不用判断是否存在写者,有读者时即开始读操//作。 WaitForSingleObject(g_hReadSemaphore,INFINITE); //等待 g_hReadSemaphore 读信号,即当 g_hReadSemaphore 有信号时等待结束 相当于 p 操作 if(g_NumOfReading ==0) { WaitForSingleObject(g_hWriteSemaphore,INFINITE); //当第一个读者到了,如果 g_hWriteSemaphore 信号灯灭了,说明有写者再写,读者必须等待。即互斥写操作 } g_NumOfReading++; ReleaseSemaphore(g_hReadSemaphore,1,NULL); //还有读者,但是允许下一个读进程读取, 相当于 V 操作// modify the reader's real start time pPerson->m_nStartTime = g_CurrentTime; printf("Reader %d is Reading the Shared Buffer...\n",pPerson->m_nID); printf("\n\n************************************************\n"); while(g_CurrentTime < pPerson->m_nStartTime + pPerson->m_nWorkTime) { // .. perform read operations } printf("Reader %d is Exit...\n",pPerson->m_nID); //printf("\n\n************************************************\n"); WaitForSingleObject(g_hReadSemaphore,INFINITE); g_NumOfReading--; if(g_NumOfReading == 0) { ReleaseSemaphore(g_hWriteSemaphore,1,NULL);//此时没有读者,可以写 } ReleaseSemaphore(g_hReadSemaphore,1,NULL); if(pPerson->m_nID == 5) finished = true; //所有的读写完成 ExitThread(0); return 0; } DWORD WINAPI WriterProc(LPVOID lpParam) { Person *pPerson = (Person*)lpParam; // wait for the start time while(g_CurrentTime != pPerson->m_nStartTime) { } printf("Writer %d is Requesting ...\n",pPerson->m_nID); //printf("\n\n************************************************\n"); //g_NumOfWriteRequest++; //在写者优先的时候需要用自加来初始信号值,而在读者优先的时是通过读者操作来控制信 号值
分享到:
收藏