OS 读者写者问题.docx
《OS 读者写者问题.docx》由会员分享,可在线阅读,更多相关《OS 读者写者问题.docx(16页珍藏版)》请在冰豆网上搜索。
OS读者写者问题
摘要
随着计算机的普及,计算机专业具有广泛的应用领域,具备数学、电子、自动化等交叉学科背景知识极为必要。
如果说这是“标配”,那么不按常理出牌的老美也允许“例外”——新东方董事王强就凭借“计算机语音和人类语言都是语言”的论断,从英语语言专业转到计算机专业。
要研究计算机科学,先要有先进的计算机,之前提到的计算机工程(CE)就是为此而设立。
从代表二进制中0和1的高低电平,到存储信息的记忆晶体;从I/O端口的读写操作,到无线连接的通信协议,这些与硬件性能相关的细节,都在CE专业的考虑范畴。
不难理解,CE专业的申请者需具备扎实的电子电路基础和一定的动手能力。
当然,这不意味着CE只关心纯“硬件”,应该说CE专业是沟通软件和硬件的桥梁,游走于电路、协议和应用软件之间,为高层的算法研究提供可靠、稳定、高效的平台。
在分析了读者-写者问题的要求,创建一个控制台进程,用信号量机制分别实现读者优先和写者优先问题。
读者写者问题是一个典型的进程同步的例子:
可以有一个或多个读者在读,不能有两个写者同时进行写操作,也不能同时有一个线程在读,而另一个线程在写。
利用C++6.0编程实现了读者写者问题的资源共享系统,其中资源共享是计算机的一项重要的功能,是目前应用最广泛用途之一。
该系统有读者优先和写者优先两种,在每个线程创建、发出读写申请、开始读写操作和结束读写操作时分别显示一行提示信息,以确定所有处理都遵守相应的读写操作限制。
关键词:
计算机;CE;读者;写者;信号量;线程;读者优先;写者优先
1引言
操作系统是最重要的计算机系统软件,同时也是最活跃的学科之一,其发展极为迅速。
在多道程序环境下,系统中可能存在许多进程,这些进程间存在着一定的制约关系。
1虽然,满足Bernstein条件的多个进程可以并发执行,从而改善资源利用率和提高系统吞吐量,但是由于进程的异步性,也会给系统造成混乱,特别是在它们争夺临界资源时。
所以,在操作系统中,必须设置相应的同步机制,使并发执行的诸进程能有效地共享资源和相互合作,从而使程序的执行具有可再现性,这就是进程同步问题。
在多道程序环境下,进程的同步问题是非常重要也相当有趣的问题,不少学者对它进行了潜心的研究,由此产生了一系列经典的进程同步问题,“读者—写者问题”就是其中之一。
读者—写者问题一个数据对象(如文件或记录),通常可被多个进程共享。
其中,有些进程只是要求读这个数据对象的内容,而另一些进程则要求对这个数据对象进行写或修改。
这种情况在文件系统、数据库中是很普通的。
通常,我们把只要求读的进程称为“reader进程”即读者,而把其它进程称为“writer进程”即写者。
很明显,几个reader进程可以同时读一个共享数据对象,不需要互斥也不会产生任何破坏数据完整性和正确性的问,但一个writer进程会独占资源,如果一个读者申请进行读操作时已有另一个写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。
1.1问题的提出
在许多现代化企业的计算机系统中,资源共享十分普遍,要保证企业的资源能够被多数员工正常的访问就要解决好读者写者的问题。
所以解决好读者写者问题对于一个机构的正常运行有着十分重要的作用,然而,用大型软件系统来于小型的企事业单位,不啻于“杀鸡用牛刀”,因此小型的的软件对于这种单位自然有十分重要作用。
某小型企业出与这种目的制作了一个资源共享系统,其中涉及到读者写者问题
1.2国内外研究的现状
关于读者写者的问题,由于研究较早,且已经成熟,没有再值得深度研究的必要,无发展空间可言。
所以,目前基本没有在继续从事相关研究的部门。
1.3任务与分析
本课题主要的目的是在Windows2000环境下,创建一个控制台进程,此进程包含n个线程。
用这n个线程来表示n个读者或写者。
每个线程按相应测试数据文件的要求进行读写操作。
用信号量机制分别实现读者优先和写者优先问题。
读者-写者问题的读写操作限制
1)写-写互斥:
不能有两个写者同时进行写操作
2)读-写互斥:
不能同时有一个线程在读,而另一个线程在写。
3)读-读允许:
可以有一个或多个读者在读。
读者优先的附加限制:
如果读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。
写者优先的附加限制:
如果一个读者申请进行读操作时已有另一个写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。
运行结果显示要求:
要求在每个线程创建、发出读写申请、开始读写操作和结束读写操作时分别显示一行提示信息,以确定所有处理都遵守相应的读写操作限制。
2需求分析
读者写者问题相关的程序在一些小型企业中应用十分广泛,主要用于小型企业内部资源共享。
因此,读者写者问题相关的程序具有较为广阔市场需求。
2.1读者优先
读者优先指的是除非有写者在写文件,否则读者不需要等待。
所以可以用一个整数变量Read_count记录当前的读者数目,用于确定是否需要释放正在等待的写者进程(当Read_count=0时,表明所有的读者读完,需要释放写者等待队列中的一个写者)。
每当一个读者开始读文件时,必须修改Read_count变量。
因此需要一个互斥对象mutex来实现对全局变量Read_count修改时的互斥。
另外,为了实现写-写互斥,需要增加一个临界区对象Write。
当写者发出写请求时,必须申请临界区对象的所有权。
通过这种方法,可以实现读-写互斥,当Read_count=1时(即第一个读者到来时),读者线程也必须申请临界区对象的所有权。
当读者拥有临界区的所有权时,写者阻塞在临界区对象Write上。
当写者拥有临界区的所有权时,第一个读者判断完”Read_count==1”后阻塞在Write上,其余的读者由于等待对Read_count的判断,阻塞在mutex上。
读者优先的附加限制:
如果读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。
2.2写者优先
写者优先与读者优先相类似。
不同之处在于一旦一个写者到来,它应该尽快对文件进行写操作,如果有一个写者在等待,则新到来的读者不允许进行读操作。
为此应当填加一个整形变量Write_count,用于记录正在等待的写者的数目,当Write_count=0时,才可以释放等待的读者线程队列。
为了对全局变量Write_count实现互斥,必须增加一个互斥对象mutex3。
为了实现写者优先,应当填加一个临界区对象read,当有写者在写文件或等待时,读者必须阻塞在read上。
读者线程除了要对全局变量Read_count实现操作上的互斥外,还必须有一个互斥对象对阻塞read这一过程实现互斥。
这两个互斥对象分别命名为mutex1,mutex2。
写者优先的附加限制:
如果一个读者申请进行读操作时已有另一个写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。
2.3显示功能
在运行界面用户可以手动输入读者优先或者写者优先的序列。
在每个线程创建、发出读写申请、开始读写操作和结束读写操作时分别显示一行提示信息,以表明所有处理都遵守相应的读写操作限制。
3程序运行平台
VC++6.0。
4总体设计
图4.1总体框架图
5详细设计
图5.1详细框架图
5.1读者优先模块
系统将提示用户输入写者优先或是读者优先选项。
//读者优先处理函数
voidReaderFun(char*file)
{
DWORDn_thread=0;//线程数初值为0
DWORDthread_ID;//线程ID
DWORDwait_for_all;//等待所有线程结束
//临界资源
HANDLEh_Mutex;
//互斥对象(h_Mutex)确保线程拥有对单个资源的互斥访问权
h_Mutex=CreateMutex(NULL,FALSE,"mutex_for_readcount");
HANDLEh_Thread[64];//线程对象数组,最大64
ThreadInfothread_info[64];
readcount=0;
InitializeCriticalSection(&RP_Write);//初始化临界区
ifstreaminFile;
inFile.open(file);
cout<<"读者优先:
\n"<while(inFile)
{//读入每一个读者、写者的信息
inFile>>thread_info[n_thread].Threadhao
>>thread_info[n_thread].ThreadClass
>>thread_info[n_thread].ThreadStartTime
>>thread_info[n_thread].ThreadRunTime;
if(-1==inFile.get())
break;
n_thread++;//线程数加一
}
for(inti=0;i<(int)(n_thread);i++)
{
if(thread_info[i].ThreadClass=='r')
//创建读者线程
h_Thread[i]=CreateThread(NULL,0,\
(LPTHREAD_START_ROUTINE)(R_ReaderThread),\
&thread_info[i],0,&thread_ID);
else
//创建写者线程
h_Thread[i]=CreateThread(NULL,0,\
(LPTHREAD_START_ROUTINE)(R_WriterThread),\
&thread_info[i],0,&thread_ID);
}
wait_for_all=WaitForMultipleObjects(n_thread,h_Thread,TRUE,-1);
cout<<"所有的读者和写者线程完成操作."<}
//读者优先-----读者线程
voidR_ReaderThread(void*p)
{
//互斥变量
HANDLEh_Mutex;
h_Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_readcount");
DWORDwait_for_mutex;//等待互斥变量所有权
DWORDm_delay;//延迟时间
DWORDm_ThreadRunTime;//读文件持续时间
intm_Threadhao;//线程序号
m_Threadhao=((ThreadInfo*)(p))->Threadhao;
m_delay=(DWORD)(((ThreadInfo*)(p))->ThreadStartTime*100);
m_ThreadRunTime=(DWORD)(((ThreadInfo*)(p))->ThreadRunTime*100);
Sleep(m_delay);//延迟等待
cout<<"读者线程"<//等待互斥对象通知
wait_for_mutex=WaitForSingleObject(h_Mutex,-1);//等待互斥信号,保证对readcount的访问、修改互斥
readcount++;//读者数目加一
if(readcount==1)
EnterCriticalSection(&RP_Write);//禁止写者进入
ReleaseMutex(h_Mutex);//释放互斥对象,允许下个读者继续读:
//读文件
cout<<"读者线程"<Sleep(m_ThreadRunTime);
//退出线程
cout<<"读者线程"<wait_for_mutex=WaitForSingleObject(h_Mutex,-1);//等待互斥信号,保证对readcount的访问、修改互斥
readcount--;//读者数目减少
if(readcount==0)
LeaveCriticalSection(&RP_Write);//如果所有读者读完,唤醒写者
ReleaseMutex(h_Mutex);//释放互斥信号
}
//读者优先-----写者线程
voidR_WriterThread(void*p)
{
DWORDm_delay;//延迟时间
DWORDm_ThreadRunTime;//读文件持续时间
intm_Threadhao;//线程序号
//从参数中获得信息
m_Threadhao=((ThreadInfo*)(p))->Threadhao;
m_delay=(DWORD)(((ThreadInfo*)(p))->ThreadStartTime*100);
m_ThreadRunTime=(DWORD)(((ThreadInfo*)(p))->ThreadRunTime*100);
Sleep(m_delay);//延迟等待
cout<<"写者线程"<EnterCriticalSection(&RP_Write);//禁止下一位写者进入
//写文件
cout<<"写者线程"<Sleep(m_ThreadRunTime);
//退出线程
cout<<"写者线程"<LeaveCriticalSection(&RP_Write);//如果所有读者读完,唤醒写者
}
5.2写有优先模块
系统将提示用户输入读者优先或是写者优先选项。
//写者优先处理函数
voidWriterFun(char*file)
{
DWORDn_thread=0;//线程数目
DWORDthread_ID;//线程ID
DWORDwait_for_all;//等待所有线程结束
//互斥对象
HANDLEh_Mutex1,h_Mutex2,h_Mutex3;
h_Mutex1=CreateMutex(NULL,FALSE,"mutex_for_writecount");
h_Mutex2=CreateMutex(NULL,FALSE,"mutex_for_readcount");
h_Mutex3=CreateMutex(NULL,FALSE,"mutex_for_read");
//线程对象数组
HANDLEh_Thread[64];
ThreadInfothread_info[64];
readcount=0;//初始化readcount
InitializeCriticalSection(&cs_Write);//初始化临界区
InitializeCriticalSection(&cs_Read);
ifstreaminFile;
inFile.open(file);//打开文件
cout<<"写者优先:
\n"<while(inFile)
{//读入每一个读者、写者的信息
inFile>>thread_info[n_thread].Threadhao
>>thread_info[n_thread].ThreadClass
>>thread_info[n_thread].ThreadStartTime
>>thread_info[n_thread].ThreadRunTime;
if(-1==inFile.get())
break;
n_thread++;//线程数加一
}
for(inti=0;i<(int)(n_thread);i++)
{
if(thread_info[i].ThreadClass=='r')
//创建读者线程
h_Thread[i]=CreateThread(NULL,0,\
(LPTHREAD_START_ROUTINE)(W_ReaderThread),\
&thread_info[i],0,&thread_ID);
else
//创建写者线程
h_Thread[i]=CreateThread(NULL,0,\
(LPTHREAD_START_ROUTINE)(W_WriterThread),\
&thread_info[i],0,&thread_ID);
}
//等待所有线程结束
wait_for_all=WaitForMultipleObjects(n_thread,h_Thread,TRUE,-1);
cout<<"所有的读者和写者线程完成操作."<}
//写者优先-----写者线程
voidW_WriterThread(void*p)
{
//互斥变量
HANDLEh_Mutex1;
h_Mutex1=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_writecount");
DWORDwait_for_mutex;//等待互斥变量所有权
DWORDm_delay;//延迟时间
DWORDm_ThreadRunTime;//读文件持时续间
intm_Threadhao;//线程序号
m_Threadhao=((ThreadInfo*)(p))->Threadhao;
m_delay=(DWORD)(((ThreadInfo*)(p))->ThreadStartTime*100);//每秒时钟中断100次
m_ThreadRunTime=(DWORD)(((ThreadInfo*)(p))->ThreadRunTime*100);
Sleep(m_delay);
cout<<"写者线程"<wait_for_mutex=WaitForSingleObject(h_Mutex1,-1);
writecount++;
if(writecount==1)
EnterCriticalSection(&cs_Read);
ReleaseMutex(h_Mutex1);
EnterCriticalSection(&cs_Write);
cout<<"写者线程"<Sleep(m_ThreadRunTime);
cout<<"写者线程"<LeaveCriticalSection(&cs_Write);
wait_for_mutex=WaitForSingleObject(h_Mutex1,-1);
writecount--;
if(writecount==0)
LeaveCriticalSection(&cs_Read);
ReleaseMutex(h_Mutex1);
}
//写者优先-----读者线程
voidW_ReaderThread(void*p)
{
HANDLEh_Mutex2,h_Mutex3;
h_Mutex2=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_readcount");
h_Mutex3=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_read");
DWORDwait_for_mutex,wait_for_mutex1;
//等待互斥变量所有权
DWORDm_delay;//延迟时间
DWORDm_ThreadRunTime;//读文件持续时间
intm_Threadhao;//线程序号
m_Threadhao=((ThreadInfo*)(p))->Threadhao;
m_delay=(DWORD)(((ThreadInfo*)(p))->ThreadStartTime*100);
m_ThreadRunTime=(DWORD)(((ThreadInfo*)(p))->ThreadRunTime*100);
Sleep(m_delay);
cout<<"读者线程"<wait_for_mutex1=WaitForSingleObject(h_Mutex3,-1);
EnterCriticalSection(&cs_Read);
LeaveCriticalSection(&cs_Read);
ReleaseMutex(h_Mutex3);
wait_for_mutex=WaitForSingleObject(h_Mutex2,-1);
readcount++;
if(readcount==1)
EnterCriticalSection(&cs_Write);
ReleaseMutex(h_Mutex2);
cout<<"读者线程"<Sleep(m_ThreadRunTime);
cout<<"读者线程"<wait_for_mutex=WaitForSingleObject(h_Mutex2,-1);
readcount--;
if(readcount==0)
LeaveCriticalSection(&cs_Write);
ReleaseMutex(h_Mutex2);
}
5.3显示模块
while(true)
{
cout<<"***************本程序实现读者-写者问题*******\n"<cout<<"1:
读者优先"<cout<<"2:
写者优先"<cout<<"3:
退出"<cout<<"\n*********************************************"<cout<<"请选择要进行的操作:
"<do
{
cin>>select;
if(select!
='1'&&select!
='2'&&select!
='3')
cout<<"你操作有误,请重试!
"<}while(select!
='1'&&select!
='2'&&select!
='3');
syste