欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

操作系统进程管理--读者写者问题

程序员文章站 2022-03-05 09:53:53
...

读者写者问题

进程互斥访问有限资源的同步问题

问题:允许多个进程同时读取文件, 但是如果有一个进程在写文件,那么就不允许其他进程写或者是读这个文件

读者优先

读者优先就是只有当所有的读者都完成了读文件的操作后,才能让写进程访问文件

实现方法:
  • readcount:读者计数器,初值为0
  • rmutex:初值为1,因为读者计数器为多个读者共享的资源,是临界资源
  • wmutex:初值为1,互斥信号量,代表一个共享文件
伪代码:
void reader(void)
{
	while(true)
    {
        p(rmutex); //抢占读者计算器这个资源
        readercount++; //读者数量加1
        //如果是第一个读者,要执行p操作抢占文件,为什么要抢占文件,就要先抢占,防止有写者进行写(读者优先),如果不是第一个读者,则表示已经有读者在安全地读这个文件
        if (readercount == 1)
            p(wmutex);  //抢占共享文件资源
        v(rmutex); //释放读者计算器
        
        read_file(); //读文件
        
        p(rmutex); //读完文件后,读者数量减少1,所以需要再次抢占读者计算器这个资源,然后进行修改
        readcount--;//读者数量减1
        if (readcount == 0) 
            //如果是最后一个读者,需要释放“共享文件”这个资源,这样才能让写者进程进行写
            v(wmutex); //释放文件资源
        v(rmutex);//释放读者计数器
            
    }
}


void write(void)
{
    while(true)
    {
        p(wmutex); //抢占文件资源
        
        write_file(); //执行写文件操作
        
        v(wmutex); //释放文件资源
    }
}

写者优先

只有当所有的写进程完成后才进行读进程的操作

  • 读者与写者,写者与写者不能同时访问缓冲区
  • 当没有写者进程的时候,多个读者进程可以同时访问缓冲区
  • 当读者进程和写者进程同时等待的时候,写者进程优先于读者进程,也就是所有的读者进程进行活动都要建立在没有写者进程的前提下
实现方法:
  • wcount:表示写者数量,初始值为0
  • rcount:表示读者数量, 初始值为0
  • rmutex:互斥修改读者数量,初始值为1
  • wmutex:互斥修改写者数量,初始值为1
  • file:互斥访问文件,初始值为1
  • read:阻塞读者进程,写者优先,当至少有一个写进程操作文件的时候,读进程就要阻塞
注意问题:

当读者队列不为0的时候,写者进程会等待这些读者进程全部读文件完后然后释放文件资源,然后才进行写文件操作,假设当读者进程执行了很久,然后读者队列中有多个,也就是rcount >=1,然后这时候写者进程1来申请写文件资源,那么他这个时候必须等待之前的读者队列内的全部读者完成操作后才行至于写者优先的操作体现在当写者进程进行申请文件资源后,有读者进程1在他之后也申请文件资源,那么这个读者进程只能排到写者进程的后面,然后不幸的是这个时候再来一个写者进程2,那么读者进程1只能被挤掉,排在写者进程2后面,也就是此时的进程队列为写者进程1,写者进程2,读者进程1.。。。 读者进程是可以有多个的,也就是读者进程申请完后,可能他的释放比另一个读者进程的申请要慢,所以就可以产生多个读者进程

伪代码:
void reader()
{
    while(true)
    {
        p(read);//当前写者队列为空的时候,就可以申请读文件资源
        p(rmutex); //抢占读者计数器
        if(rcount == 0)  //如果是第一个读者,那么就抢占文件资源,这样就可以保证读文件与写文件互斥
            p(file);  //抢占文件资源
        rcount++; //读者数量+1
        v(rmutex); //释放读者计数器
        v(read);  //这一步比较关键,如果不释放的话,那么你每次只有一个读者进程,而且写进程也不能抢占这个资源,就会发生死锁
        //而且这也是写进程抢占写文件的时机,如果写进程抢占到这个read,他就会等到之前所有的读进程完成后释放文件,然后抢占文件,进而就可以开始写进程,这也就是写者优先
          
        read_file(); //读取文件
        
        p(rmutex);//抢占读者计数器
        rcount--;
        if (rcount == 0)  //如果是最后一个读者进程,释放文件资源
            v(file);
        v(rmutex); //释放读者计数器              
    }
}

void writer(void)
{
    while(true)
    {
        p(wmutex); //抢占写者计数器
        if (wcount == 0) //如果当前写者队列为空,申请优先资源
            p(read)
         wcount++; //写者数量加1
        v(wmutex); //释放写者计数器
        
        p(file); //申请文件资源,这时候写者会等待在他进程之前的所有读者进程完成后释放文件
        
        write_file(); //写文件
        
        v(file); //释放文件
        
        p(wmutex); //抢占写者计数器
        wcount--; // 写者数量减1
        if (wcount == 0) //如果是最后一个写者
            v(read); //释放优先资源
        v(wmutex); //释放写者计数器  
    }
}

读者写者(读写公平)–先来先服务

实现方法
  • 信号量 file 初始值为1, //用于实现对文件的互斥操作
  • readcount = 0; //记录读者个数
  • 信号量 readmutex 初始值为1,对readcount 互斥访问
  • 信号量 s 实现读写公平
伪代码
void reader()
{
    while (1)
    {
        p(s);
        p(readmutex);
        if (readcount == 0)
            p(file);
        readcount++;
        v(readmutex);
        v(s);
        读文件
        p(readmutex);
        if (readcount==0)
            v(file);
        v(readmutex);
    }
}

void writer()
{
    while (1)
    {
        p(s);
        p(file);
        写文件;
        v(file);
        v(s);
    }
}
测试并发情况
  • 读者1 —读者2
  • 写1 — 写2
  • 读 1 --写1
  • 写1 —读1
  • 读1 —写1—读2