文档库 最新最全的文档下载
当前位置:文档库 › 读者写者

读者写者

读者写者
读者写者

读者/写者实验报告

――多线程的实现

一、实验要求

在Windows 2000/XP环境下,创建一个控制台进程,此进程包含n 个线程。用这n 个线程来表示n 个读者或写者。每个线程按相应测试数据文件(格式见下)的要求进行读写操作。用信号量机制分别实现读者优先和写者优先的读者/写者问题(详见课本5.7)。

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

测试数据文件格式如下:

测试数据文件包括n 行测试数据,分别描述创建的n 个线程是读者还是写者,以及读写操作的开始时间和持续时间。每行测试数据包括4个字段,各个字段间用空格分隔。

●第一个字段为一个正整数,表示线程序号

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

●第三个字段为一个正数,表示读/写操作的开始时间:线程创建后,延迟相应时间(单

位为秒)后发出对共享资源的读/写请求

●第四个字段为一正数,表示读/写操作的持续时间:线程读写请求成功后,开始对共享

资源的读/写操作,该操作持续相应时间后结束,并释放共享资源

例如:

1 R 3 5

2 W 4 5

3 R 5 2

4 R 6 5

5 W 5.1 3

二、实验理解分析与设计

1.进程和线程

在Windows32位操作系统中,所谓多任务是指系统可以同时运行多个进程,而每个进程也可以同时执行多个线程。

所谓进程就是应用程序的运行实例。每个进程都有自己私有的虚拟地址空间。每个进程都有一个主线程,但可以建立另外的线程。进程中的线程是并发执行的,每个线程占用CPU 的时间由系统来划分。我们可以把线程看成是操作系统分配CPU时间的基本实体。

进程中的所有线程共享进程的虚拟地址空间,这意味着所有线程都可以访问进程的全局变量和资源。这一方面为编程带来了方便,但另一方面也容易造成冲突。

虽然在进程中进行费时的工作不会导致系统的挂起,但这会导致进程本身的挂起。所以,如果进程既要进行长期的工作,又要响应用户的输入,那么它可以启动一个线程来专门负责费时的工作,而主线程仍然可以与用户进行交互。

2.线程的同步

多线程的使用会产生一些新的问题,主要是如何保证线程的同步执行。多线程应用程序需要使用同步对象和等待函数来实现同步。同步问题是实现远程数据采集或远程自动控制编程中的关键技术问题。

3.同步的原因

由于同一进程的所有线程共享进程的虚拟地址空间,并且线程的中断是汇编语言级的,所以可能会发生两个线程同时访问同一个对象(包括全局变量、共享资源、API函数和MFC 对象等)的情况,这有可能导致程序错误。例如,如果一个线程在未完成对某一大尺寸全局变量的读操作时,另一个线程又对该变量进行了写操作,那么第一个线程读入的变量值可能是一种修改过程中的不稳定值。

属于不同进程的线程在同时访问同一内存区域或共享资源时,也会存在同样的问题。

因此,在多线程应用程序中,常常需要采取一些措施来同步线程的执行。

4.同步的方法

由于线程间需要同步机制,才能协调运行。在Windows32编程中,主要提供了以下几种方法。

等待函数

这些函数只有在作为其参数的一个或多个同步对象产生信号时才会返回。在超过规定的等待时间后,不管有无信号,函数也都会返回。在等待函数未返回时,线程处于等待状态,此时线程只消耗很少的CPU时间。

使用等待函数即可以保证线程的同步,又可以提高程序的运行效率。最常用的等待函数是WaitForSingleObject,该函数的声明为:

DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);

参数hHandle是同步对象的句柄。参数dwMilliseconds是以毫秒为单位的超时间隔,如果该参数为0,那么函数就测试同步对象的状态并立即返回,如果该参数为INFINITE,则超时间隔是无限的。

同步对象

同步对象用来协调多线程的执行,它可以被多个线程共享。线程的等待函数用同步对象的句柄作为参数,同步对象应该是所有要使用的线程都能访问到的。同步对象的状态要么是有信号的,要么是无信号的。同步对象主要有三种:事件、mutex和信号灯。

事件对象(Event)是最简单的同步对象,它包括有信号和无信号两种状态。在线程访问某一资源之前,也许需要等待某一事件的发生,这时用事件对象最合适。例如,只有在通

信端口缓冲区收到数据后,监视线程才被激活。

Mutex对象的状态在它不被任何线程拥有时是有信号的,而当它被拥有时则是无信号的。mutex对象很适合用来协调多个线程对共享资源的互斥访问(mutually exclusive)。

信号灯对象维护一个从0开始的计数,在计数值大于0时对象是有信号的,而在计数值为0时则是无信号的。信号灯对象可用来限制对共享资源进行访问的线程数量。线程用CreateSemaphore函数来建立信号灯对象,在调用该函数时,可以指定对象的初始计数和最大计数。在建立信号灯时也可以为对象起个名字,别的进程中的线程可以用OpenSemaphore 函数打开指定名字的信号灯句柄。

临界区和互锁变量的访问

临界区(Critical Seciton)与mutex的功能类似,但它只能由同一进程中的线程使用。临界区可以防止共享资源被同时访问。

进程负责为临界区分配内存空间,临界区实际上是一个CRITICAL_SECTION型的变量,它一次只能被一个线程拥有。在线程使用临界区之前,必须调用InitializeCriticalSection函数将其初始化。如果线程中有一段临界的代码不希望被别的线程中断,那么可以调用EnterCriticalSection函数来申请临界区的所有权,在运行完临界代码后再用LeaveCriticalSection函数来释放所有权。如果在调用EnterCriticalSection时临界区对象已被另一个线程拥有,那么该函数将无限期等待所有权。

利用互锁变量可以建立简单有效的同步机制。使用函数InterlockedIncrement和InterlockedDecrement可以增加或减少多个线程共享的一个32位变量的值,并且可以检查结果是否为0。线程不必担心会被其它线程中断而导致错误。如果变量位于共享内存中,那么不同进程中的线程也可以使用这种机制。

5.本实验的分析

由题目要求可知,这是一个实现多线程的使用,要求多个读者线程和多个写者线程共享读写临界区,而各个读者线程共享读进程资源,各个写线程共享写进程资源,所以这里包含了两个层次的共享,不凡把读写线程共享的临界区称为全局临界区,所有读线程共享的读进程的临界资源称为局部读临界区,所有写线程共享的写进程的临界资源称为局部写临界区。具体的关系如下图所示:

根据题目的要求还可以知道,在一个进程下的多个线程的并发情况:同是读进程的不同线程可以同时访问读写全局临界区,但是同时写进程的不同线程每次只能一个访问该读写全

局临界区,还有就是读写线程不能同时访问读写全局临界区。

6.实验的设计

根据以上的进程和线程的理解以及对线程同步机制的分析,结合本次实验的特点,我设计出了以下的方案:

读线程间和写线程间对各自局部共享资源的访问修改采用Mutex对象,结合

WaitForSingleObject保证互斥操作。

读线程与写线程争用全局临界资源采用临界区(Critical Seciton)。

统管读写线程的线程采用WaitForMultipleObjects保证等待所有的线程结束。

三、源程序

#include

#include

#include

#include

#include

#define MAX_THREAD_NUM 64

#define FILENAME "Thread.dat"

int cur_time;

int start_time;

//全局变量Global variable

int readcount;

int writecount;

//定义临界区Define the critical section

CRITICAL_SECTION RP_Write;//读者优先的"写临界区"

CRITICAL_SECTION WP_Read;//写者优先的"读临界区"

CRITICAL_SECTION WP_Write;//写者优先的"写临界区"

//定义读写进程的参数的结构Define the datastructure of the parameter

//of the read_process and write_process

struct ThreadInfo{

int ID;

char mode;

double delayTime;

double runTime;

};

//定义进程数组和参数数组Define the arrays for the process and parameter

HANDLE h_Thread[MAX_THREAD_NUM];

ThreadInfo thread_info[MAX_THREAD_NUM];

//声明函数Functions Declaration

//读者优先的处理函数The functions for the ReadPriority mode

void ReadPriority(char* file);

void RP_Reader(void* p);//参数void* p指示任何结构类型的参数

//Parameter void* p stands for all diffrent kinds of parameter

void RP_Writer(void* p);

//写者优先的处理函数The functions for the WritePriority mode

void WritePriority(char* file);

void WP_Reader(void* p);

void WP_Writer(void* p);

void help()

{

printf("#######################################################\n");

printf("#########Enter the number 1 2 3 for a run mode#########\n");

printf("######### 1 ReadPriority 读者优先#########\n");

printf("######### 2 WritePriority 写者优先#########\n");

printf("######### 3 Help 帮助#########\n");

printf("######### 4 Quit 退出#########\n");

printf("#######################################################\n"); }

int main()

{

char mode;

help();

while(1){

do{

cin>>mode;

}while(mode<'1'||mode>'4');

switch(mode){

case '1':

ReadPriority(FILENAME);

break;

case '2':

WritePriority(FILENAME);

break;

case '3':

help();

break;

case '4':

return 0;

}

return 0;

}

//读者优先处理函数的函数体The function body of the work function for ReadPriority

void ReadPriority(char* file)

{

DWORD nThreadcount=0;//Thread number

DWORD nThreadId;

DWORD wait_for_all;//等待所有线程的结束

//初始化,Initialization

readcount=writecount=0;

InitializeCriticalSection(&RP_Write);

ifstream infile;

infile.open(file);

while(infile){

infile>>thread_info[nThreadcount].ID;

infile>>thread_info[nThreadcount].mode;

infile>>thread_info[nThreadcount].delayTime;

infile>>thread_info[nThreadcount].runTime;

nThreadcount++;

infile.get();

}

infile.close();

start_time=clock();

//creat all the thread 创建所有的线程

for(int i=0;i<(int)nThreadcount;i++){

if(thread_info[i].mode=='R'||thread_info[i].mode=='r'){//creat a read thread

h_Thread[i]=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(RP_Reader),

&thread_info[i], 0, &nThreadId);

//printf("A reader thread created, run ID is %d\n",nThreadId);

//cout<<"The "<

}else{//creat a write thread

h_Thread[i]=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(RP_Writer),

&thread_info[i], 0, &nThreadId);

//printf("A writer thread created, run ID is %d\n",nThreadId);

//cout<<"The "<

}

//等待所有的线程结束wait for all the thread to finish

wait_for_all=WaitForMultipleObjects((int)nThreadcount,h_Thread,1,-1);

//printf("All the threads finish!\n");

cur_time=clock();

cout<<"All the threads finish at time "<<(cur_time-start_time)/1000.0<<" !\n";

}

void RP_Reader(void* p)

{

HANDLE h_Mutex;//互斥变量

h_Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_readcount");//保证各个读线程对readcount的修改的互斥

DWORD wait_for_mutex; //等待互斥变量所有权

DWORD nDelay; //延迟时间

DWORD nRun; //读文件持续时间

int nSerial; //线程序号

nSerial=((ThreadInfo*)(p))->ID;

nDelay=((ThreadInfo*)(p))->delayTime*1000;

nRun=((ThreadInfo*)(p))->runTime*1000;//单位是毫秒

//delay time 延迟时间

Sleep(nDelay);

cur_time=clock();

//printf("Reader thread %d sends the reading require!\n",nSerial);

cout<<"Reader thread "<

//发出读请求

wait_for_mutex=WaitForSingleObject(h_Mutex,-1);//保证只能有一个读线程修改readcount

//参数-1表明不会由于超时而使函数返回

readcount++;

if(readcount==1)

EnterCriticalSection(&RP_Write);//由于是读者优先,所以要阻止write线程的访问ReleaseMutex(h_Mutex);//释放互斥对象

//开始读操作

cur_time=clock();

cout<<"Reader thread "<

Sleep(nRun);

cur_time=clock();

cout<<"Reader thread "<

wait_for_mutex=WaitForSingleObject(h_Mutex,-1);

readcount--;

if(readcount==0)

LeaveCriticalSection(&RP_Write);

ReleaseMutex(h_Mutex);

}

void RP_Writer(void* p)

{

DWORD nDelay; //延迟时间

DWORD nRun; //读文件持续时间

int nSerial; //线程序号

nSerial=((ThreadInfo*)(p))->ID;

nDelay=((ThreadInfo*)(p))->delayTime*1000;

nRun=((ThreadInfo*)(p))->runTime*1000;//单位是毫秒

//delay time 延迟时间

Sleep(nDelay);

cur_time=clock();

cout<<"Writer thread "<

EnterCriticalSection(&RP_Write);

cur_time=clock();

cout<<"Writer thread "<

Sleep(nRun);

cur_time=clock();

cout<<"Writer thread "<

LeaveCriticalSection(&RP_Write);

}

///////////////////////////////////

//写者优先处理函数的函数体The function body of the work function for WritePriority

void WritePriority(char* file)

{

//代码类似于ReadPriority();只是CreatThread的时候入口地址不同而已

DWORD nThreadcount=0;//Thread number

DWORD nThreadId;

DWORD wait_for_all;//等待所有线程的结束

//初始化,Initialization

readcount=writecount=0;

InitializeCriticalSection(&WP_Read);

InitializeCriticalSection(&WP_Write);

//printf("All the threads finish!\n");

ifstream infile;

infile.open(file);

while(infile){

infile>>thread_info[nThreadcount].ID;

infile>>thread_info[nThreadcount].mode;

infile>>thread_info[nThreadcount].delayTime;

infile>>thread_info[nThreadcount].runTime;

nThreadcount++;

infile.get();

}

infile.close();

start_time=clock();

//creat all the thread 创建所有的线程

for(int i=0;i<(int)nThreadcount;i++){

if(thread_info[i].mode=='R'||thread_info[i].mode=='r'){//creat a read thread

h_Thread[i]=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(WP_Reader),

&thread_info[i], 0, &nThreadId);

//printf("A reader thread created, run ID is %d\n",nThreadId);

//cout<<"The "<

}else{//creat a write thread

h_Thread[i]=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(WP_Writer),

&thread_info[i], 0, &nThreadId);

//printf("A writer thread created, run ID is %d\n",nThreadId);

//cout<<"The "<

}

}

//等待所有的线程结束wait for all the thread to finish

wait_for_all=WaitForMultipleObjects((int)nThreadcount,h_Thread,1,-1);

//printf("All the threads finish!\n");

cur_time=clock();

cout<<"All the threads finish at time "<<(cur_time-start_time)/1000.0<<" !\n";

}

void WP_Reader(void* p)

{

HANDLE h_Mutex;//互斥变量

h_Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_readcount");

//保证各个读线程对readcount的修改的互斥

DWORD wait_for_mutex; //等待互斥变量所有权

DWORD nDelay; //延迟时间

DWORD nRun; //读文件持续时间

int nSerial; //线程序号

nSerial=((ThreadInfo*)(p))->ID;

nDelay=((ThreadInfo*)(p))->delayTime*1000;

nRun=((ThreadInfo*)(p))->runTime*1000;//单位是毫秒

//delay time 延迟时间

Sleep(nDelay);

cur_time=clock();

//printf("Reader thread %d sends the reading require!\n",nSerial);

cout<<"Reader thread "<

//发出读请求

EnterCriticalSection(&WP_Read);//申请WP_Read临界区,如果已经有写者存在则阻塞该读线程

wait_for_mutex=WaitForSingleObject(h_Mutex,-1);//保证只能有一个读线程修改readcount

//参数-1表明不会由于超时而使函数返回

readcount++;

if(readcount==1)

EnterCriticalSection(&WP_Write);//阻止write线程的访问

ReleaseMutex(h_Mutex);//释放互斥对象,允许其它WP_Reader线程对readcount的修改LeaveCriticalSection(&WP_Read);//这里就要释放临界区,因为允许多个读线程同时读//开始读操作

cur_time=clock();

cout<<"Reader thread "<

Sleep(nRun);

cur_time=clock();

cout<<"Reader thread "<

wait_for_mutex=WaitForSingleObject(h_Mutex,-1);

readcount--;

if(readcount==0)

LeaveCriticalSection(&WP_Write);

ReleaseMutex(h_Mutex);

}

void WP_Writer(void* p)

{

HANDLE h_Mutex;

DWORD nDelay; //延迟时间

DWORD nRun; //读文件持续时间

int nSerial; //线程序号

DWORD wait_for_mutex;

h_Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_writecount");

//保证各个写线程对writecount的修改的互斥

nSerial=((ThreadInfo*)(p))->ID;

nDelay=((ThreadInfo*)(p))->delayTime*1000;

nRun=((ThreadInfo*)(p))->runTime*1000;//单位是毫秒

//delay time 延迟时间

Sleep(nDelay);

cur_time=clock();

cout<<"Writer thread "<

wait_for_mutex=WaitForSingleObject(h_Mutex,-1);

writecount++;

if(writecount==1)

EnterCriticalSection(&WP_Read);//阻塞读线程

ReleaseMutex(h_Mutex);

//申请写临界区

EnterCriticalSection(&WP_Write);

cur_time=clock();

cout<<"Writer thread "<

Sleep(nRun);//写操作

cur_time=clock();

cout<<"Writer thread "<

LeaveCriticalSection(&WP_Write);

wait_for_mutex=WaitForSingleObject(h_Mutex,-1);

writecount--;

if(writecount==0)

LeaveCriticalSection(&WP_Read);//解除阻塞的读线程

ReleaseMutex(h_Mutex);

}

四、测试数据和测试结果1.测试数据

1 R 3 5

2 W 4 5

3 R 5 2

4 R 6 5

5 W 5.1 3

6 R 4.5 4

2.测试结果

(1)初始帮助图

(2)读者优先

(3)写者优先

五、实验心得体会与提高

多进程和多线程是当今操作系统的一个很大的特色。Windows2000和Linux都是典型的多进程多线程的操作系统。

本次实验就是通过一个读进程和一个写进程生成的多个读线程和多个写线程的并发执行来理解和体会Windows的多线程处理机制。

由于是初次接触涉及系统内部的程序设计,开始的时候,我感觉到有点茫然,因为我不知道从哪里下手开始我的实验。我很认真地研读了老师提供的材料,以期得到启发,但是还是觉得“万事开头难”,我虽然有些理解了,但是还不是很清晰,也就是说我的脑中还没有形成一个具体的程序架构。我看了材料中的那些函数,比如WaitForSingleObject、WaitForMutipleObjects、CreatThread等等,我总的试验一下它们才知道怎样用啊,于是我随便写了一个例子,用材料中的函数组合成为一个有点模样的程序,在慢慢的摸索之中,加上通过自己到图书馆查阅资料、上网查阅资料、查看MSDN的帮助文档,最终还是把问题理解得更加透彻了,心中也有了一个整体的架构,下面的工作就显得胸有成竹、代码的实现也就得心应手。

实验的作用就是使自己对学过的知识的理解得到加深,同时巩固对知识的掌握,最终要把知识转化为实际的应用。在本次实验的过程中,我充分的感受到了学习一种新的知识以及把这种新的知识消化为己之所有,特别是要转化为实际应用根本是两个不同层次的概念,这也启迪了我今后无论学习什么,都应该在知其然的基础上深入研究,要知其所以然,如果要更进一步就要积极的把知识转化为应用。

就本次实验来说,难度并不是很大,为什么呢?因为如果理解了就不觉得难了!但是是否真的不难呢?如果从另一个角度来看,实验是一个非常难的实验,现在觉得不难是因为我们可以直接调用Windows API函数(这当然要在我们理解了的基础上),但是如果没有API 函数,我们还能觉得不难吗?其实这也是一个知其然而不知其所以然的问题,我们通过API 接口,可以很方便地创建新的线程(CreatThread),可以很容易的实现互斥的访问

(WaitForSingleObject),同样可以很“糊涂”地控制对临界资源的访问(EnterCriticalSection),为什么说“糊涂”呢?因为我们只是知道这样可以达到目的,但是这个API接口的内部是怎样实现以达到该目的的呢?我们不知道,所以只能“胡里胡涂”的使用。当然,在绝大多数的情况下,懂得很准确很巧妙的利用API接口就足够了,但是如果能更加深入的了解就更好了。其实这一点我也没有做到,毕竟那是一件非常不简单的事情,而且我们目前也没有办法得到这些API接口的源程序,也就无法推敲它们实现的机制。所以尽管实验已经完成了,我还是觉得实验没有完成,至少没有真正的完成,因为我们还要学习的东西实在太多了,这次实验给了很多的触动,我现在还在思考着,如果要我自己实现这些线程的互斥以及阻塞线程、解除线程阻塞等等,我应该怎样实现呢?我正在思考着这样的问题。

确实如上面所说的,我们现在只是使用API,但是还不了解API的内部实现,因此就会引发一些困惑,比如说利用我的程序测试一个写者优先的数据的时候,我很奇怪的发现:在存在写线程访问“临界资源”的时候,或者已经在等待访问“临界资源”的时候,所有的读线程的申请访问都会被阻塞(例子中的W2已经在等待,因此R6、R3、R4的申请分别被阻塞)一直等到W2结束,还要W5结束的时候,R6、R3、R4才得到解除阻塞,注意这里的顺序,由于R6、R3、R4的申请顺序是R6、R3、R4,因此我预期它们得以访问“临界资源”的顺序也是R6、R3、R4,但是测试结果刚好倒过来,显示是R4、R3、R3分别进入“临界区”(由于读线程之间不要求互斥,可以看成同时进入,但是毕竟还是要有一个先后顺序,尽管间隔时间很短),如下图所示:

为什么呢?难道那个阻塞队列是一个后进先出的队列(应该说是栈了)?我不知道,因为我看不到API的源码。引发了这样的问题也就引发了相应的思考,这种思考是非常有意义的,从这种思考中学习到新的知识也是非常有乐趣的。

总的来说,这次实验的收获很大,不但使得自己对操作系统的多进程多线程管理有了更加深入了理解,而且使得自己学会了更多、更有效的学习方法。实验过程中,遇到不明白的地方,我能够很好地利用图书馆的资源、利用网络的资源。在从不知到知,从知之甚少到知之甚多的过程中,或者说在知其然到知其所以然的过程中,我不但学到了知识,而且学到了学习的方法,这才是最重要的。

六、参考资料

【1】[美]William Stallings。魏迎梅、王涌译。操作系统-内核与设计原理。电子工业出版社。北京。2005

【2】管建和、夏军宝。Windows程序设计。人民邮电出版社。北京。2002

计算机科学与技术C班

詹志辉

033511168

java实现读者写者问题(写着优先)

实验一实验报告 学号:20092128 姓名:徐卓远 实验序号:1 实验名称:用信号量来实现读者-写者问题 实验目的:理解进程同步与互斥的概念,掌握用信号量来实现进程的同步与互斥。 实验设计及实现: 为了实现读者和写者的读写过程,将每个读者和每个写者作为了一个单独的线程,所以设置了两个类,一个是读者类Reader,一个是写者类Writer.以读者类为例: 一个读者的动作过程为由睡眠->等待->开始读->结束读->睡眠的一个循环过程,而一个写者的动作过程也为此. 读者调用方法napping()进行等待,调用startRead()方法开始读,最后在调用endReading()方法结束读入,释放运行空间.写者同读者. 但是为了实现读者写者之间的写-写互斥,读-写互斥,读-读允许,需要另外一个类Database,类中分别用关于读者的方法和写者的方法来控制读写之间的这种关系. 首先要实现睡眠的方法napping(),读者和写者在睡眠过程都应该是一样的,只是他们睡眠的时间不同,所以只需写出一个方法: public static void napping() {

int sleepTime = (int) (NAP_TIME * Math.random()); try { Thread.sleep(sleepTime * 1000); } catch (Exception e) { e.printStackTrace(); } } 在方法中,控制线程休眠随机的时间,由于每个读者或写者都是一个线程,而每个读者或写者他们工作休眠的时间都不一定相同,他们请求工作的时间也不一定相同,所以取了随机时间其次设置了读者的两个方法,开始读和结束读,由于这只是个模拟读写问题,所以只需要知道结果就行,就不用显示出他是怎么读的. 在开始读中,当有写者在写时,读者需要等待wait(),在没有人在工作时,如果有写者和读者同时请求,那么就让写者先进,这是写者优先.所以这就归纳于一种情况, 当读者布尔变量dbReading为FALSE时,如果有需要工作的写者,那么读者就等待. 当读者请求读入后,计数有多少读者需要工作的变量readerCount +1,如果这是第一个进入工作的读者就需要将显示是否有读者在工作的读者布尔变量变为TRUE. public synchronized int startRead() { if (dbReading == false) {

读者写者课程设计

目录 第一章课程设计目的和要求?错误!未定义书签。 1.1 课程设计目的?错误!未定义书签。 1.2 课程设计要求 0 第二章课程设计任务内容?错误!未定义书签。 2.1课程设计任务......................................... 错误!未定义书签。 2.2课程设计内容?1 第三章详细设计说明?错误!未定义书签。 3.1问题描述?错误!未定义书签。 3.2模块设计?错误!未定义书签。 3.3程序流程图?错误!未定义书签。 3.4算法与数据结构....................................... 错误!未定义书签。 3.4.1数据结构..................................... 错误!未定义书签。 3.4.2算法描述..................................... 错误!未定义书签。 3.4.3算法流程图 (5) 第四章软件使用说明.......................................... 错误!未定义书签。 4.1系统开发与运行环境?错误!未定义书签。 4.2系统的运行说明?错误!未定义书签。 4.3 运行结果 (9) 第五章课程设计心得体会...................................... 错误!未定义书签。附录1:参考文献?错误!未定义书签。 附录2:程序清单.............................................. 错误!未定义书签。

第一章课程设计目的和要求 1.1课程设计目的 操作系统是计算机系统的核心和灵魂,是计算机系统必不可少的组成部分,也是计算机专业教学的重要内容。该课程概念众多、内容抽象、灵活性与综合性强,不但需要理解操作系统的概念和原理,还需要加强操作系统实验,上机进行编程实践,故进行此次课程设计,使我们更好地掌握操作系统的精髓,真正做到深刻理解和融会贯通。 操作系统课程设计是本课程重要的实践教学环节。课程设计的目的,一方面使学生更透彻地理解操作系统的基本概念和原理,使之由抽象到具体;另一方面,通过课程设计加强学生的实验手段与实践技能,培养学生独立分析问题、解决问题、应用知识的能力和创新精神。此次课程设计给学生更多自行设计、自主实验的机会,充分放手让学生真正培养学生的实践动手能力,全面提高学生的综合素质。 本次课程设计的题目为读者写者同步问题的实现,在熟练掌握进程同步原理的基础上,利用C程序设计语言在windows操作系统下模拟实现读者写者同步问题的功能,一方面加深对原理的理解,另一方面提高根据已有原理通过编程解决实际问题的能力,为进行系统软件开发和针对实际问题提出高效的软件解决方案打下基础。 1.2课程设计要求 在深入理解操作系统基本原理的基础上,对于选定的题目以小组为单位,先确定设计方案,设计系统的数据结构和程序结构,设计每个模块的处理流程。要求设计合理,编程序实现系统,要求实现可视化的运行界面,界面应清楚地反映出系统的运行结果,确定测试方案,对系统进程测试,运行系统并要通过验收,讲解运行结果,说明系统的特色和创新之处,并提交课程设计报告。

读者和写者问题

学 号: 课 程 设 计 2014——2015学年 第1学期 课程名称 操作系统 学 院 计算机科学与技术学院 专 业 软件工程专业 班 级 姓 名 指导教师

目录 目录 .................................................................................................................................... 错误!未定义书签。 1 设计概述 (3) 1.1问题描述: (3) 1.2问题解读及规则制定 (3) 2课程设计目的及功能 (3) 2.1 设计目的 (3) 2.2 设计功能 (3) 3模块介绍 (3) 3.1函数原型 (3) 3.2 PV操作代码 (4) 4测试用例,运行结果与运行情况分析 (6) 4.1测试用例 (6) 4.2运行结果 (7) 4.3运行情况分析 (9) 5自我评价与总结 (9) 6 参考文献 (10) 7 附录:(完整代码) (10)

实现读者写者(Reader-Writer Problem)问题 1 设计概述 1.1问题描述: 通过研究Linux的线程机制和信号量实现读者写者(Reader-Writer)问题并发控制。 1.2问题解读及规则制定 一个数据文件或记录可被多个进程所共享,我们将其中只要求读该文件的进程称为读者,其他进程称为写者.多个读者和多个写者进程在某个时间段内对该文件资源进行异步操作,也就是说允许多个进程同时读一个共享对象,但不允许一个写进程和其他读进程或写进程同时访问共享对象,因此,所谓"读者--写者问题"就是指必须保证一个写进程和其他进程(写进程或者读进程)互斥地访问共享对象的同步问题.两者的读写操作限制规则如下: (1)写--写互斥,即不允许多个写着同时对文件进行写操作 (2)读--写互斥,即不允许读者和写者同时对文件分别进行读写操作 (3)读—读允许,即允许多个读者同时对文件进行读操作 2课程设计目的及功能 2.1 设计目的 通过实验模拟读者和写者之间的关系,了解并掌握他们之间的关系及其原理。由此增加对进程同步的问题的了解。具体如下: 1)掌握基本的同步互斥算法,理解读者和写者模型 2)了解多线程的并发执行机制,线程间的同步和互斥 2.2 设计功能: 利用模拟用信号量机制实现读者和写者问题:通过用户控制读进程和写进程,反应读者和写者问题中所涉及的进程的同步与互斥。 3模块介绍 3.1函数原型 读者和写者进程由11个函数组成,分别如下: (附件包含全部具体实现) void P_write(int); void write(int); void V_write(int); void P_radd(int);

实验二 读者写者问题实验报告..

实验二读者写者问题实验报告 一、实验目的 Windows2000/XP提供了互斥量(mutex)、信号量(semapore)、事件(event)等三种同步对象和相应的系统调用,用于线程的互斥与同步。通过对读者写者问题的调试,了解Windows2000/XP中的同步机制。 二、实验内容及实验步骤 利用Windows2000/XP信号量机制,实现读者写者问题。 在Windows 2000环境下,创建一个控制台进程,此进程包含n个线程。用这n个线程来表示n个读者或写者。每个线程按相应测试数据文件(后面有介绍)的要求进行读写操作。用信号量机制分别实现读者优先和写者优先的读者-写者问题。 读者-写者问题的读写操作限制(包括读者优先和写者优先): 写-写互斥,即不能有两个写者同时进行写操作。 读-写互斥,即不能同时有一个线程在读,而另一个线程在写。 读-读允许,即可以有一个或多个读者在读。 读者优先的附加限制:如果一个读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。 写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态才能开始读操作。 运行结果显示要求:要求在每个线程创建、发出读写操作申请、开始读写操作和结果读写操作时分别显示一行提示信息,以确定所有处理都遵守相应的读写操作限制。 三、实验结果及分析 图2.1 选择界面 第一字段为一个正整数,表示线程序号。第二字段表示相应线程角色,R 表示读者是,W 表示写者。第三字段为一个正数,表示读写操作的开始时间。线程创建

后,延时相应时间(单位为秒)后发出对共享资源的读写申请。第四字段为一个正数,表示读写操作的持续时间。当线程读写申请成功后,开始对共享资源的读写操作,该操作持续相应时间后结束,并释放共享资源。下面是一个测试数据文件的例子: 1 R 3 5 2 W 4 5 3 R 5 2 4 R 6 5 5 W 5.1 3 测试结果如下: 图2.2 读者优先运行结果

读者写者问题课程设计说明书

-- 数学与计算机学院 课程设计说明书 课程名称: 操作系统原理-课程设计课程代码: 题目:读者写者问题 年级/专业/班: 学生姓名: 学号: 开始时间:2011 年12月05日完成时间:2011 年12月25 日课程设计成绩: 学习态度及平时成绩(30) 技术水平与实际 能力(20) 创新(5)说明书撰写质量(45) 总分 (100) 指导教师签名:年月日

目录 1 引言?错误!未定义书签。 1.1问题的提出?错误!未定义书签。 1.2任务于分析?错误!未定义书签。 2程序的主要功能?错误!未定义书签。 2.1测试文本录入功能.................................... 错误!未定义书签。 2.2读者优先判断功能.................................... 错误!未定义书签。2.3写者优先判断功能.................................. 错误!未定义书签。 3 程序运行平台........................................... 错误!未定义书签。 4 总体设计............................................... 错误!未定义书签。5模块分析 ............................................... 错误!未定义书签。 5.1测试文本录入模块.................................... 错误!未定义书签。 5.2读者优先判断模块.................................... 错误!未定义书签。 5.3写者优先判断模块.................................... 错误!未定义书签。6系统测试............................................. 错误!未定义书签。 7 结论................................................................. 8致谢.................................................. 错误!未定义书签。参考文献 (10)

操作系统课程设计(采用读写平等策略的读者写者问题)完整版--内含代码

淮北师范大学 课程设计 采用读写平等策略的读者写者问题 学号: 姓名: 专业: 指导教师: 日期:

目录 第1部分课设简介 (3) 1.1 课程设计题目 (3) 1.2 课程设计目的.................. 错误!未定义书签。 1.3 课程设计内容 (3) 1.4 课程设计要求 (4) 1.5 时间安排 (4) 第2部分实验原理分析 (4) 2.1问题描述 (4) 2.2算法思想 (5) 2.3主要功能模块流程图 (5) 第3部分主要的功能模块 (6) 3.1数据结构 (6) 3.2测试用例及运行结果 (7) 第4部分源代码 (7) 第5部分总结及参考文献 (22) 5.1 总结 (22) 5.2 参考文献 (23)

第1部分课设简介 1.1 课程设计题目 采用读写平等策略的读者写者问题 1.2课程设计目的 操作系统课程设计是计算机专业重要的教学环节,它为学生提供了一个既动手又动脑,将课本上的理论知识和实际有机的结合起来,独立分析和解决实际问题的机会。 1)进一步巩固和复习操作系统的基础知识。 2)培养学生结构化程序、模块化程序设计的方法和能力。 3)提高学生调试程序的技巧和软件设计的能力。 4)提高学生分析问题、解决问题以及综合利用C语言进行课程设计的能力。 1.3课程设计内容 用高级语言编写和调试一个采用“读写平等”策略的“读者-- 写者”问题的模拟程序。 1.4课程设计要求 1)读者与写者至少包括ID、进入内存时间、读写时间三项内容,可在界面上进行输入。

2) 读者与写者均有两个以上,可在程序运行期间进行动态增加 读者与写者。 3)可读取样例数据(要求存放在外部文件中),进行读者/写者、 进入内存时间、读写时间的初始化。 4) 要求将运行过程用可视化界面动态显示,可随时暂停,查看 阅览室中读者/写者数目、读者等待队列、读写时间、等待时间。 5) 读写策略:读写互斥、写写互斥、读写平等(严格按照读 者与写者到达的顺序进入阅览室,有写着到达,则阻塞后续到 达的读者;有读者到达,则阻塞后续到达的写者)。 1.5时间安排 1)分析设计贮备阶段(1 天) 2)编程调试阶段(7 天) 3)写课程设计报告、考核(2 天) 第2部分实验原理分析2.1问题描述 有一个被许多进程共享的数据区,这个数据区可以是一个文件,或者主存的一块空间,甚至可以是一组处理器寄存器。有一些只读取这个数据区的进程reader和一些只往数据区中写数据的进程writer 以下假设共享数据区是文件。这些读者和写者对数据区的操作必须满

操作系统读者写者实验报告

《操作系统》上机实验报告 实验项目读者写者 学院(部)信息学院 专业计算机科学与技术班级 学生姓名 学号

读者写者问题 一.实验目的: 1.熟悉读者优先和写者优先的过程。 2.更好地理解进程同步的概念及其实现方法。 二.实验要求: 分别实现读者优先和写者优先。 “读-写”互斥,即不能同时有一个读者在读,同时去有一个写者在写; “写-写”互斥,即不能有两个写者同时进行写操作; “读-读”允许,即可以有两个以上的读者同时进行读操作。 三.实验内容: 读者优先: 如果没有写者正在操作,则读者不需要等待,用一个整型变量readcount 记录当前的读者数目,用于确定是否释放写者线程,(当readcout=0 时,说明所有的读者都已经读完,释放一个写者线程),每个读者开始读之前都要修改readcount,为了互斥的实现对readcount 的修改,需要一个互斥对象Mutex来实现互斥。 另外,为了实现写-写互斥,需要一个临界区对象write,当写者发出写的请求时,必须先得到临界区对象的所有权。通过这种方法,可以实现读写互斥,当readcount=1 时,(即第一个读者的到来时,),读者线程也必须申请临界区对象的所有权. 当读者拥有临界区的所有权,写者都阻塞在临界区对象write上。当写者拥有临界区对象所有权时,第一个判断完readcount==1 后,其余的读者由于等待对readcount的判断,阻塞在Mutex上! 写者优先: 写者优先和读者优先有相同之处,不同的地方在:一旦有一个写者到来时,应该尽快让写者进行写,如果有一个写者在等待,则新到的读者操作不能读操作,为此添加一个整型变量writecount,记录写者的数目,当writecount=0时才可以释放读者进行读操作!为了实现对全局变量writecount的互斥访问,设置了一个互斥对象Mutex3。 为了实现写者优先,设置一个临界区对象read,当有写者在写或等待时,读者必须阻塞在临界区对象read上。 读者除了要一个全局变量readcount实现操作上的互斥外,还需要一个互斥对象对阻塞在read这一个过程实现互斥,这两个互斥对象分别为mutex1和mutex2。

操作系统OS报告读者与写者问题(进程同步问题)

目录 一、课程设计目的及要求 (1) 二、相关知识 (1) 三、题目分析 (2) 四、概要设计 (4) 五、代码及流程 (5) 六、运行结果 (11) 七、设计心得 (12) 八、参考文献 (12)

一、课程设计目的及要求 读者与写者问题(进程同步问题) 用n 个线程来表示n个读者或写者。每个线程按相应测试数据文件的要求,进行读写操作。请用信号量机制分别实现读者优先和写者优先的读者-写者问题。 读者-写者问题的读写操作限制: 1)写-写互斥; 2)读-写互斥; 3)读-读允许; 写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。 二、相关知识 Windows API: 在本实验中涉及的API 有: 1线程控制: CreateThread 完成线程创建,在调用进程的地址空间上创建一个线程,以执行指定的函数;它的返回值为所创建线程的句柄。 HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD DWORD dwStackSize, // initial stack size LPTHREAD_START_ROUTINE lpStartAddress, // thread function LPVOID lpParameter, // thread argument DWORD dwCreationFlags, // creation option LPDWORD lpThreadId // thread identifier ); 2 ExitThread 用于结束当前线程。 VOID ExitThread( DWORD dwExitCode // exit code for this thread ); 3Sleep 可在指定的时间内挂起当前线程。 VOID Sleep( DWORD dwMilliseconds // sleep time ); 4信号量控制: WaitForSingleObject可在指定的时间内等待指定对象为可用状态; DWORD WaitForSingleObject( HANDLE hHandle, // handle to object DWORD dwMilliseconds // time-out interval );

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

操作系统课程设计 课题:读者写者问题 姓名:赫前进 班级:1020552 学号102055211 指导教师:叶瑶 提交时间:2012/12/30

(一)实验目的 1.进一步理解“临界资源”的概念; 2.把握在多个进程并发执行过程中对临界资源访问时的必要约束条件; 3.理解操作系统原理中“互斥”和“同步”的涵义。 (二)实验内容 利用程序设计语言编程,模拟并发执行进程的同步与互斥(要求:进程数目不少于3 个)。 (三)、程序分析 读者写者问题的定义如下:有一个许多进程共享的数据区,这个数据区可以是一个文件或者主存的一块空间;有一些只读取这个数据区的进程(Reader)和一些只往数据区写数据的进程(Writer),此外还需要满足以下条件: (1)任意多个读进程可以同时读这个文件; (2)一次只有一个写进程可以往文件中写; (3)如果一个写进程正在进行操作,禁止任何读进程度文件。 实验要求用信号量来实现读者写者问题的调度算法。实验提供了signal类,该类通过P( )、V( )两个方法实现了P、V原语的功能。实验的任务是修改Creat_Writer()添加写者进程,Creat_Reader()创建读者进程。Reader_goon()读者进程运行函数。读优先:要求指一个读者试图进行读操作时,如果这时正有其他读者在进行操作,他可直接开始读操作,而不需要等待。 读者优先的附加限制:如果一个读者申请进行读操作时已有另一读者正在进行读操作,则该读者可直接开始读操作。 写优先:一个读者试图进行读操作时,如果有其他写者在等待进行写操作或正在进行写操作,他要等待该写者完成写操作后才开始读操作。 写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。 在Windows 7 环境下,创建一个控制台进程,此进程包含n 个线程。用这n 个线程来表示n 个读者或写者。每个线程按相应测试数据文件(格式见下)的要求进行读写操作。用信号量机制分别实现读者优先和写者优先的读者/写者问题。

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

操作系统课程设计报告

一、开题报告 (一)该项课程设计的意义; 1.更加深入的了解读者写者问题的算法; 2.加深对线程,进程的理解; 3.加深对“线程同步”概念的理解,理解并应用“信号量机制”; 4.熟悉计算机对处理机的管理,了解临界资源的访问方式; 5.了解C++中线程的实现方式,研读API。 (二)课程设计的任务 多进程/线程编程:读者-写者问题。 ●设置两类进程/线程,一类为读者,一类为写者; ●随机启动读者或写者; ●显示读者或写者执行状态; ●随着进程/线程的执行,更新显示; (三)相关原理及算法描述; 整体概况: 该程序从大体上来分只有两个模块,即“读者优先”和“写者优先”模块. 读者优先: 如果没有写者正在操作,则读者不需要等待,用一个整型变量readcount记录读者数目,用于确定是否释放读者线程,readcount的初值为0.当线程开始调入时. 每个读者准备读. 等待互斥信号,保证对readcount 的访问,修改互斥.即readcount++. 而当读者线程进行读操作时,则读者数目减少(readcount--).当readcout=0 时,说明所 有的读者都已经读完,离开临界区唤醒写者(LeaveCriticalSection(&RP_Write);), 释 放互斥信号(ReleaseMutex(h_Mutex)). 还需要一个互斥对象mutex来实现对全局变量Read_count修改时的互斥. 另外,为了实现写-写互斥,需要增加一个临界区对象Write。当写者发出写请求时, 必须申请临界区对象的所有权。通过这种方法,可以实现读-写互斥,当 Read_count=1时(即第一个读者到来时),读者线程也必须申请临界区对象的所有 权 写者优先: 写者优先与读者不同之处在于一旦一个写者到来,它应该尽快对文件进行写操作,如果有一个写者在等待,则新到来的读者不允许进行读操作。为此应当填加 一个整形变量write_count,用于记录正在等待的写者的数目,write_count的初值 为0.当线程开始调入时.只允许一个写者准备读. 等待互斥信号,保证对write_count 的访问,修改互斥.即write_count++.而当写者线程进行读操作时,则相应写者数目减 少(write_count--).当write_count=0 时,说明所有的读者都已经读完,离开临界区唤 醒读者,释放互斥信号. 为了实现写者优先,应当填加一个临界区对象read,当有写者在写文件或等待时,读者必须阻塞在read上。

面向对象OS读者-写者问题

2.读者—写者问题 读者—写者问题(Readers-Writers problem)也是一个经典的并发程序设计问题,是经常出现的一种同步问题。计算机系统中的数据(文件、记录)常被多个进程共享,但其中某些进程可能只要求读数据(称为读者Reader);另一些进程则要求修改数据(称为写者Writer)。就共享数据而言,Reader和Writer是两组并发进程共享一组数据区,要求: (1)允许多个读者同时执行读操作; (2)不允许读者、写者同时操作; (3)不允许多个写者同时操作。 Reader和Writer的同步问题分为读者优先、弱写者优先(公平竞争)和强写者优先三种情况,它们的处理方式不同。

(1)读者优先。对于读者优先,应满足下列条件: 如果新读者到: ①无读者、写者,新读者可以读; ②有写者等待,但有其它读者正在读,则新读者也可以读; ③有写者写,新读者等待。 如果新写者到: ①无读者,新写者可以写; ②有读者,新写者等待; ③有其它写者,新写者等待。 单纯使用信号量不能解决读者与写者问题,必须引入计数器rc 对读进程计数; rc_mutex 是用于对计数器rc 操作的互斥信号量;write表示是否允许写的信号量;于是读者优先的程序设计如下: int rc=0; //用于记录当前的读者数量 semaphore rc_mutex=1; //用于对共享变量rc 操作的互斥信号量 semaphore write=1; //用于保证读者和写者互斥地访问的信号量 void reader() /*读者进程*/ do{ P(rc_mutex); //开始对rc共享变量进行互斥访问 rc ++; //来了一个读进程,读进程数加1 if (rc==1) P(write);//如是第一个读进程,判断是否有写进程在临界区, //若有,读进程等待,若无,阻塞写进程 V(rc_mutex); //结束对rc共享变量的互斥访问 读文件; P(rc_mutex); //开始对rc共享变量的互斥访问 r c--; //一个读进程读完,读进程数减1 if (rc == 0) V(write);//最后一个离开临界区的读进程需要判断是否有写进程//需要 进入临界区,若有,唤醒一个写进程进临界区 V(rc_mutex); //结束对rc共享变量的互斥访问 } while(1) void writer() /*写者进程*/ do{ P(write); //无读进程,进入写进程;若有读进程,写进程等待写文件; V(write); //写进程完成;判断是否有读进程需要进入临界区, //若有,唤醒一个读进程进临界区 } while(1) 读者优先的设计思想是读进程只要看到有其它读进程正在读,就可以继续进行读;写进程必须等待所有读进程都不读时才能写,即使写进程可能比一些读进程更早提出申请。该算法只要还有一个读者在活动,就允许后续的读者进来,该策略的结果是,如果有一个稳定的读者流存在,那么这些读者将在到达后被允许进入。而写者就始终被挂起,直到没有读者为止。

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

操作系统课程设计报告 一、操作系统课程设计任务书 读者- 写者问题实现 1设计目的通过实现经典的读者写者问题,巩固对线程及其同步机制的学习效果,加深对相关基本概念的理解,并学习如何将基本原理和实际设计有机的结合。 2设计要求 在Windows 2000/XP 环境下,使用多线程和信号量机制实现经典的读者写者问题,每个线程代表一个读者或一个写者。每个线程按相应测试数据文件的要求,进行读写操作。请用信号量机制分别实现读者优先和写者优先的读者- 写者问题。 读者-写者问题的读写操作限制: (1)写-写互斥,即不能有两个写者同时进行写操作 (2)读-写互斥,即不能同时有一个读者在读,同时却有一个写者在写 (3)读-读允许,即可以有二个以上的读者同时读读者优先的附加限制:如果一个读者申请进行读操作时已有另一读者正在进行读操作,则该读者可直接开始读操作。 写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。 运行结果显示要求:要求在每个线程创建、发出读写操作申请、开始读写操作和结束读写操作时分别显示一行提示信息,以确信所有处理都遵守相应的读写操作限制。 3测试数据文件格式 测试数据文件包括n 行测试数据,分别描述创建的n 个线程是读者还是写者,以及读写操作的开始时间和持续时间。每行测试数据包括四个字段,各字段间用空格分隔。第一字段为一个正整数,表示线程序号。第二字段表示相应线程角色,R 表示读者是,W 表示写者。第三字段为一个正数,表示读写操作的开始时间。线程创建后,延时相应时间(单位为秒)后发出对共享资源的读写申请。第四字段为一个正数,表示读写操作的持续时

操作系统实验 读者写者问题

《计算机操作系统》实验报告 题目读者写者问题 学院(部)信息学院 专业计算机科学与技术 班级 学生姓名 学号 指导教师(签字)

一、问题描述 一个数据文件或者记录,可以被多个进程共享,我们把只要求读该文件的进程称为“Reader进程”,其他进程则称为“Writer进程”。允许多个进程同时读一个共享对象,因为读操作不会是数据文件混乱。但不允许一个Writer进程和其他Reader进程或者Writer进程同时访问共享对象,因为这种访问将会引起混乱。所谓“读者——写着问题(Reader—Writer Problem)”是指保证一个Writer进程必须与其他进程互斥地访问共享对象的同步问题 二、解决问题 为实现Reader与Writer进程间在读或写是的互斥而设置了一个互斥的信号量Wmutex。另外,在设置一个整型变量Readcount表示正在读的进程数目。由于只要有一个Reader进程在读,便不允许Writer去写。因此,仅当Readercount=0时,表示尚无Reader进程在读时,Reader进程才需要进行Wait(wmutex)操作。若Wait(Wmutex)操作成功,Reader进程便可去读,相应地,做Readcount+1操作。同理,仅当Reader进程在执行了Readercount-1操作后其值为0时,才执行Signal(Wmutex)操作,以便让Writer进程写。又因为Readercount是一个可被多个Reader进程访问的临界资源,因此也应该为它设置一个互斥信号量rmutex。 三、代码实现 1、读者优先 #include #include using namespace std; CRITICAL_SECTION rmutex,wmutex; int wr; int readernum; DWORD WINAPI reader(LPVOID IpParamter){ cout<<"读者申请\n"; wr++; EnterCriticalSection(&rmutex); if(readernum==0) EnterCriticalSection(&wmutex); readernum++; cout<<"读者进入成功正在读取\n"; LeaveCriticalSection(&rmutex); Sleep(2000); EnterCriticalSection(&rmutex); readernum--; cout<<"读者退出\n"; wr--;

读者写者问题

一设计概述 所谓读者写者问题,是指保证一个writer进程必须与其他进程互斥地访问共享对象的同步问题。 读者写者问题可以这样的描述,有一群写者和一群读者,写者在写同一本书,读者也在读这本书,多个读者可以同时读这本书,但是,只能有一个写者在写书,并且,读者必写者优先,也就是说,读者和写者同时提出请求时,读者优先。当读者提出请求时需要有一个互斥操作,另外,需要有一个信号量S来当前是否可操作。 信号量机制是支持多道程序的并发操作系统设计中解决资源共享时进程间的同步与互斥的重要机制,而读者写者问题则是这一机制的一个经典范例。 与记录型信号量解决读者—写者问题不同,信号量机制它增加了一个限制,即最多允许RN个读者同时读。为此,又引入了一个信号量L,并赋予初值为RN,通过执行wait(L,1,1)操作,来控制读者的数目,每当有一个读者进入时,就要执行wait(L,1,1)操作,使L的值减1。当有RN个读者进入读后,L便减为0,第RN+1 个读者要进入读时,必然会因wait(L,1,1)操作失败而堵塞。对利用信号量来解决读者—写者问题的描述如下: Var RN integer;L,mx:semaphore: =RN,1; Begin Parbegin Reader :begin Repeat Swait(L,1,1); Swait(mx,1,0); . Perform reader operation; Ssignal(L,1); Until false; End

Writer :begin Repeat Swait(mx ,1,1,l,RN,0); Perform writer operation; Ssignal(mx,1); Until false; End Parend End 其中,Swait(mx,1,0)语句起着开关作用,只要无Writer进程进入些,mx=1,reader进程就都可以进入读。但是要一旦有Writer进程进入写时,其MX=0,则任何reader进程就都无法进入读。Swait(mx ,1,1,l,RN,0)语句表示仅当既无Write 进程在写(mx=1),又无reader进程在读(L=RN)时,writer进程才能进入临界区写。 本设计方案就是通过利用记录型信号量对读者写者问题的解决过程进行模拟演示,形象地阐述记录型信号量机制的工作原理。 二设计目的与内容 一实验目的 l. 用信号量来实现读者写者问题。 2. 理解和运用信号量、PV原语、进程间的同步互斥关系等基本知识。二、二实验内容 读者写者问题的定义如下:有一个许多进程共享的数据区,这个数据区可以是一个文件或者主存的一块空间;有一些只读取这个数据区的进程(Reader)和一些只往数据区写数据的进程(Writer),此外还需要满足以下条件:(1)任意多个读进程可以同时读这个文件; (2)一次只有一个写进程可以往文件中写; (3)如果一个写进程正在进行操作,禁止任何读进程度文件。

题目3-读者与写者问题

实验3 读者/写者问题与进程同步 3.1 实验目的 理解临界区和进程互斥的概念,掌握用信号量和PV操作实现进程互斥的方法。 3.2 实验要求 在linux环境下编写一个控制台应用程序,该程序运行时能创建N个线程,其中既有读者线程又有写者线程,它们按照事先设计好的测试数据进行读写操作。请用信号量和PV操作实现读者/写者问题。 读者/写者问题的描述如下: 有一个被许多进程共享的数据区,这个数据区可以是一个文件,或者主存的一块空间,甚至可以是一组处理器寄存器。有一些只读取这个数据区的进程(reader)和一些只往数据区中写数据的进程(writer)。以下假设共享数据区是文件。这些读者和写者对数据区的操作必须满足以下条件:读—读允许;读—写互斥;写—写互斥。这些条件具体来说就是:(1)任意多的读进程可以同时读这个文件; (2)一次只允许一个写进程往文件中写; (3)如果一个写进程正在往文件中写,禁止任何读进程或写进程访问文件; (4)写进程执行写操作前,应让已有的写者或读者全部退出。这说明当有读者在读文件时不允许写者写文件。 对于读者-写者问题,有三种解决方法: 1、读者优先 除了上述四个规则外,还增加读者优先的规定,当有读者在读文件时,对随后到达的读者和写者,要首先满足读者,阻塞写者。这说明只要有一个读者活跃,那么随后而来的读者都将被允许访问文件,从而导致写者长时间等待,甚至有可能出现写者被饿死的情况。 2、写者优先 除了上述四个规则外,还增加写者优先的规定,即当有读者和写者同时等待时,首先满足写者。当一个写者声明想写文件时,不允许新的读者再访问文件。 3、无优先 除了上述四个规则外,不再规定读写的优先权,谁先等待谁就先使用文件。 3.3算法分析 3.3.1读者优先 对于相继到达的一批读者,并不是每个读者都需要执行P(r_w_w)和V(r_w_w)。在这批读者中,只有最先到达的读者才需要执行P(r_w_w),与写者竞争对文件的访问权,若执行P(r_w_w)成功则获得了文件的访问权,其他的读者可直接访问文件;同理,只有最后退出临界区的读者需要执行V(r_w_w)来归还文件访问权。 为了记录正在读文件的一批读者的数量,需要设置一个整型变量readercount,每一个读者到达时都要将readercount加1,退出时都要将readercount减1。 由于只要有一个读者在读文件,便不允许写者写文件,所以,仅当readercount=0时,即尚无读者在读文件时,读者才需要执行P(r_w_w)操作。若P(r_w_w)操作成功,读者便可去读文件,相应地,readercount+1。同理,仅当在执行了readercount减1操作后其值为0时,才需要执行V(r_w_w)操作,以便让写者写文件。又因为readercount是一个可被多个读者访问的临界资源,所以应该为它设置一个互斥信号量readercount_mutex.。每个读者在访

北理工操作系统实验二读者写者问题

本科实验报告 实验名称:操作系统原理实验(读者写者问题) 课程名称:操作系统原理实验时间:2015.10.30 任课教师:王耀威实验地点:10#102 实验教师:苏京霞 实验类型: 原理验证□综合设计□自主创新 学生姓名:孙嘉明 学号/班级:1120121474/05611202 组号:学院:信息与电子学院同组搭档:专业:信息对抗技术成绩:

实验二:读者写者问题 一、实验目的 1.通过编写和调试程序以加深对进程、线程管理方案的理解; 2.熟悉Windows多线程程序设计方法; 二、实验要求 在Windows环境下,创建一个控制台进程,此进程包含n个线程。用这n个线程来表示n个读者或写者。每个线程按相应测试数据文件(后面介绍)的要求进行读写操作。用信号量机制分别实现读者优先和写者优先问题。 读者-写者问题的读写操作限制(包括读者优先和写者优先) 1)写-写互斥:不能有两个写者同时进行写操作 2)读-写互斥:不能同时有一个线程在读,而另一个线程在写。 3)读-读允许:可以有一个或多个读者在读。 读者优先的附加限制:如果读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。 运行结果显示要求:要求在每个线程创建、发出读写申请、开始读写操作和结束读写操作时分别显示一行提示信息,以确定所有处理都遵守相应的读写操作限制。 测试数据文件包括 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

读者写者问题写者优先代码

读者写者问题-写者优先代码 #include<stdio.h> #include<stdlib.h> int rcount=0;//正在读的读者数量 int wcount=0;//写者队列中等待写操作的写者数量 int rid=0;//读进程号 int wid=0;//写进程号 int w=1;//读写互斥信号量 char temp[300] = {'\0'}; int sign; //标识temp空的信号量0表示temp空 void WFwakeup(); void RFwakeup(); struct rqueue{//读者等待队列 int readers[200]; int index; }rq; struct wqueue{//写者等待队列 int writers[200]; int index; }wq; void read(){ int i = 0; rid++; if(rcount == 0){//当前没有读进程在读可能有写进程在写可能CPU空闲if(w==1) {//如果CPU空闲,读者拿到CPU w--;// 相当于一个P操作 rcount++; if(temp[0] == '\0'){ sign = 0; rq.readers[rq.index++]=rid;//将读者进程加入等待队列 WFwakeup(); return; }//if printf("读者%d正在读\n",rid);

for(i = 0;i < 300;i++){//读取temp内容即写者写的内容 if(temp[i] == '\0'){ printf("\n"); return; }//if printf("%c",temp[i]); }//for }//if else{//写者线程正在执行 printf("有写者在写不能读!\n"); rq.readers[rq.index++]=rid;//将读者进程加入等待队列 }//else }//if else{//rcount !=1 则知道当前已经有读者在读,读读不互斥,则这个读者可以直接进来了读 printf("读者%d正在读\n",rid); for(i = 0;i < 300;i++){ if(temp[i] == '\0'){ printf("\n"); return; } printf("%c",temp[i]); }//for }//else } //***************************写进程写操作 void write(){ wid++; if(w == 0){ if(rcount != 0 ){//有读者进程在执行 printf("有读者在读不能写!\n"); wq.writers[wq.index++]=wid;//将写者进程加入等待队列 wcount++; return; } if(rcount == 0 ){//rcount == 0则当前无读者,但w = 0,所以有写者在写 printf("有写者在写不能写!\n"); wq.writers[wq.index++]=wid;//将写者进程加入等待队列 wcount++; return; } }

相关文档
相关文档 最新文档