读者-写者问题

本文深入探讨了读者-写者问题,分析了读写进程的互斥与同步需求,提出了两种解决方案,一种以读者优先,另一种以写者优先,通过设置信号量和计数器实现了复杂的互斥问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 问题描述

有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。

因此要求:

①允许多个读者可以同时对文件执行读操作;
②只允许一个写者往文件中写信息;
③任一写者在完成写操作之前不允许其他读者或写者工作;
④写者执行写操作前,应让已有的读者和写者全部退出。
在这里插入图片描述

2 问题分析
  1. 关系分析。找出题目中描述的各个进程,分析它们之间的同步、互斥关系。

两类进程:写进程、读进程
互斥关系:写进程一写进程、写进程一读进程。读进程与读进程不存在互斥问题。

  1. 整理思路。根据各进程的操作流程确定P、V操作的大致顺序
  1. 写者与任何进程互斥,用互斥信号量的PV操作即可解决,读者问题较为复杂,它必须在实现与写者互斥的同时实现与其他读者的同步,因此一对简单的PV操作是无法解决问题;
  2. 这里用到一个计数器,用它判断当前是否有读者读文件,当有读者时,写者无法写文件,此时读者一直占用文件,当没有读者时,写者才可以写文件;
  3. 同时不同读者对计数器的访问也是互斥的。
  1. 设置信号量。设置需要的信号量,并根据题目条件确定信号量初值。(互斥信号量初值一般为1,同步信号量的初始值要看对应资源的初始值是多少)
semaphore rw=1; //用于保证读者和写者对共享文件的互斥访问 
int count = 0; //用于记录当前有几个读进程访问在共享文件 
semaphore mutex = 1;//用于保证对count数量的互斥访问
3 代码实现
semaphore rw=1;       //用于保证读者和写者对共享文件的互斥访问 
int count = 0;        //用于记录当前有几个读进程访问在共享文件 
semaphore mutex = 1;  //用于保证对count数量的互斥访问

writer(){
	whlie(1){
       P(rw);      //互斥访问共享文件
       写入;
       V(rw);     //释放共享文件
   }
}

reader(){
    whlie(1){
        P(mutex)             //互斥访问count变量
        if(count==0)
            P(rw);       //阻止写进程写入
        count++;
        V(mutex);    //释放互斥变量count
        读取;
        P(mutex);     //互斥访问count变量
        count--if(count==0)      //当最后一个读进程读完共享文件
            V(rw);     //允许写进程写
         V(mutex);    //释放互斥变量count       
    }
}

分析:上述代码中读进程优先,即当存在读进程时,写操作将会被延迟,且只要有一个读进程活跃,随后而至的读进程都将会被允许访问文件,这样的方式会导致写进程可能长时间等待,且存在写进程饿死情况

若希望写进程优先,即当有读进程正在访问共享文件时,有写进程请求访问,这是应禁止后续读进程的请求,等到已在共享文件中的读进程执行完毕,立即让写进程执行,只有在无写进程执行的情况下才允许读进程再次运行。
为此,增加一个信号量并在上面程序的writer()reader()函数中各增加一对PV操作,即可得到写进程优先的解决程序。

semaphore rw=1;       //用于保证读者和写者对共享文件的互斥访问 
int count = 0;        //用于记录当前有几个读进程访问在共享文件 
semaphore mutex = 1;  //用于保证对count数量的互斥访问
semaphore w=1;        //实现写进程优先

writer(){
	whlie(1){
	   P(w);       //在无写进程请求时进入
       P(rw);      //互斥访问共享文件
       写入;
       V(rw);     //释放共享文件
       V(w);       //恢复对共享文件的访问
   }
}

reader(){
    whlie(1){
        P(w);       //在无写进程请求时进入
        P(mutex)          //互斥访问count变量
        if(count==0)
            P(rw);     //阻止写进程写入
        count++;
        V(mutex);    //释放互斥变量count
        V(w);       //恢复对共享文件的访问
        读取;
        P(mutex);     //互斥访问count变量
        count--if(count==0)      //当最后一个读进程读完共享文件
            V(rw);     //允许写进程写
         V(mutex);    //释放互斥变量count       
    }
}

读者-写者问题为我们解决复杂的互斥问题提供了一个参考思路
其核心思想在于设置一个计数器count用来记录当前正在访问共享文件的读进程数。我们可以用count值来判断当前进入的进程是否谁第一个/最后一个读进程,从而做出不同的处理

另外,对count变量的检查和赋值不能一气呵成会导致一些错误,若需要实现一气呵成,自然需要设置互斥信号量
最后还需认真体会如何解决“写进程饥饿”问题

初始条件: 1操作系统:Linux 或者 windows 2程序设计语言:C,java语言 3设有20个连续的存储单元,入/读出的数据项按增序设定为1-20这20个字符。 要求完成的主要任务: (包括课程设计工作量及其技术要求,以及说明书撰等具体要求) 1.技术要求: 1)为每个读者者产生一个线程,设计正确的同步算法 2)每个读者/者对该存储区进行操作后,即时显示该存储区的全部内容、当前指针位置和读者/者线程的自定义标识符。。 3)读者应有3个以上,者应有有两个以上。 4)多个读者/者之间须共享对存储区进行操作的函数代码。 2. 设计说明书内容要求: 1)设计题目与要求 2)总的设计思想及系统平台、语言、工具等。 3)数据结构与模块说明(功能与流程图) 4)给出用户名、源程序名、目标程序名和源程序及其运行结果。(要注明存储各个程序及其运行结果的主机IP地址和目录。) 5)运行结果与运行情况 (提示: (1)连续存储区可用数组实现。 (2)编译命令可用:     cc -lpthread -o  目标文件名  源文件名 (3)多线程编程方法参见附件。) 3. 调试报告: 1) 调试记录 2) 自我评析和总结 上机时间安排: 19周一 ~ 五 下午14:00 - 18:00 (6月27日开始) 指导教师签名: 年 月 日 系主任(或责任教师)签名: 年 月 日 五、源代码 #include #include #include "fstream.h" int readcount=0; //读者数目 int writecount=0; //者数目 CRITICAL_SECTION RP_Write; //临界区 CRITICAL_SECTION cs_Write; CRITICAL_SECTION cs_Read; struct ThreadInfo //线程信息 { int Threadhao; //线程序号 char ThreadClass; //线程类别 double ThreadStartTime; //线程开始时间 double ThreadRunTime; //线程读持续时间 }; void ReaderFun(char* file);//读者优先函数 void R_ReaderThread(void *p);//处理读者优先读者线程 void R_WriterThread(void *p);//处理读者优先者线程 void WriterFun(char* file); void W_ReaderThread(void *p); void W_WriterThread(void *p); int main()//主函数 { char select; while (true) { cout<<"***************本程序实现读者-问题*******\n"<<endl; cout<<" 1:读者优先"<<endl; cout<<" 2:者优先"<<endl; cout<<" 3:退出"<<endl; cout<<"\n*********************************************"<<endl; cout<<"请选择要进行的操作:"<>select; if(select!='1' && select!='2' && select!='3') cout<<"你操作有误,请重试!"<<endl; }while (select!='1' && select!='2' && select!='3'); system("cls"); if (select=='3') return 0;//退出 else if (select=='1')//调用读者优先 ReaderFun("peizhi.txt"); else if(select=='2')//调用者优先 WriterFun("peizhi.txt"); cout<<"\n是否还有继续? 1. 继续 2.退出"<>select; if(select!='1' && select!='2' ) cout<<"你操作有误,请重试!"<<endl; }while (select!='1' && select!='2'); if(select=='2') return 0;// 退出 system("cls"); } return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值