操作系统:读者写者问题

读者写者问题描述:

读者只会读取数据,不会修改数据,而写者即可以读也可以修改数据。

  1. 同一时刻,允许多个读者同时读
  2. 没有写者时读者才能读,没有读者时写者才能写
  3. 没有其他写者时,写者才能写

1、读者优先

代码实现:

semaphore wMutex; //写操作的互斥信号量,初始值为1
semaphore rCountMutex; //对读者的互斥修改,初始值为1
int rCount = 0;  //正在进行读操作的读者个数,初始化为0


void writer( )
{
    while(TRUE){
        P( wMutex); //进入临界区write( );

        /*
        *进行写操作
        */

        V(wMutex);//进入临界区
     }
}
void reader( )
{
    while(TRUE){
        P(rCountMutex);//进入临界区
        if ( rCount == 0)
        {
            P(wMutex);//如果有写者,则阻塞写者
        }
        rCount++    //读者计数+1
        V(rCountMutex );//离开临界区

       /*
        *进行读操作
        */

        P(rCountMutex);//进入临界区
        rCount--;//读完数据,准备离开
    if ( rCount == 0)
    {
        V( wMutex);//最后一个读者离开了,则唤醒写者
    }
    V( rCountMutex ) ;//离开临界区
    }
}

上面的这种实现,是读者优先的策略,因为只要有读者正在读的状态,后来的读者都可以直接进入,如果读者持续不断进入,则写者就无法得到运行。

2、写者优先

那既然有读者优先策略,自然也有写者优先策略:

  1. 只要有写者准备要写入,写者应尽快执行写操作,后来的读者就必须阻塞;
  2. 如果有写者持续不断写入,则读者就处于饥饿状态,一直无法进行读操作;

代码实现:

semaphore rCountMutex;//控制对Rcount的互斥修改,初始值为1
semaphore rMutex;//控制读者进入的互斥信号量者,初始值为 1

semaphore wCountMutex//控制 wCount互斥修改,初始值为1
semaphore wDataMutex//控制写者写操作的互斥信号量,初始值为1

int rCount = 0; //正在进行读操作的读者个数,初始化为0
int wCount = 0;//正在进行读操作的写者个数,初始化为0


void writer()
{
  while(TRUE)
  {
    P(wCountMutex);//进入临界区
    if ( wCount ==0 )
    {
        P( rMutex);1/当第一个写者进入,如果有读者则阻塞读者
    }
    wCount++; //写者计数+1
    V(wCountMutex);//离开临界区

    P( wDataMutex);//写者写操作之间互斥,进入临界区
    /*
    *进行写操作
    */
    V(wDataMutex);    //离开临界区

    P(wCountMutex);    //进入临界区
    wCount--;    //写完数据,准备离开
    if (wCount == 0 )
    {
        V(rMutex);// 最后一个写者离开了,则唤醒读者
    }
    V(wCountMutex);//离开临界区
  }
}



void reader()
{
 while(TRUE)
  {
    P(rMutex);
    P(rCountMutex);//进入临界区
    if ( rCount == 0)
    {
        P(wDataMutex);//当第一个读者进入,如果有写者则阻塞写者写操作
    }
    rCount++;
    V(rCountMutex);//离开临界区
    V(rMutex);

    /*
    *进行读操作
    */

    P(rCountMutex);//进入临界区
    rCount--;
    if (rCount == 0)
    {
        V(wDataMutex);//当没有读者了,则唤醒阻塞中写者的写操作
    }
    v(rCountMutex);//离开临界区
 }
}

注意,这里rMute的作用,开始有多个读者读数据,它们全部进入读者队列,此时来了一个写者,执行了 P(rMute) 之后,后续的读者由于阻塞在 rMute 上,都不能再进入读者队列,而写者到来,则可以全部进入写者队列,因此保证了写者优先。

同时,第一个写者执行了 P(rMute) 之后,也不能马上开始写,必须等到所有进入读者队列的读者都执行完读操作,通过V(wDataMutex)唤醒写者的写操作。

3、读者写者公平策略

 要求:

  1. 优先级相同;
  2. 写者、读者互斥访问;
  3. 只能一个写者访问临界区;
  4. 可以有多个读者同时访问临界资源;

具体代码实现:

semaphore rCountMutex; //控制对Rcount的互斥修改,初始值为1
semaphore wDataMutex  //控制写者写操作的互斥信号量,初始值为1
semaphore flag;   //用于实现公平竞争,初始值为1
int rCount = 0;   //正在进行读操作的读者个数,初始化为0


void writer()
{
  while(TRUE)
  {
    P( flag );
    P(wDataMutex);//写者写操作之间互斥,进入临界区

    /*
    *进行写操作
    */

    V(wDataMutex); //离开临界区
    V(flag);
 }
}


void reader( )
{
  while(TRUE)
  {
    P(flag);
    P(rCountMutex);//进入临界区
    if (rCount==0)
    {
        P(wDataMutex);//当第一个读者进入,如果有写者则阻塞写者写操作
    }
    rCount++;
    V(rCountMutex);//离开临界区
    V(flag);

    /*
    *进行写操作
    */

    P(rCountMutex ); //进入临界区
    rCount--;
    if (rCount == 0)
    {
        V(wDataMutex);//当没有读者了,则唤醒阻塞中写者的写操作
    }
    V(rCountMutex); //离开临界区
  }
}

对比方案一的读者优先策略,可以发现,读者优先中只要后续有读者到达,读者就可以进入读者队列, 而写者必须等待,直到没有读者到达。

没有读者到达会导致读者队列为空,即 rCount==0,此时写者才可以进入临界区执行写操作。

而这里 flag 的作用就是阻止读者的这种特殊权限(特殊权限是只要读者到达,就可以进入读者队列)。

比如:开始来了一些读者读数据,它们全部进入读者队列,此时来了一个写者,执行 P(flag) 操作,使得后续到来的读者都阻塞在 flag 上,不能进入读者队列,这会使得读者队列逐渐为空,即 rCount 减为 0。

这个写者也不能立马开始写(因为此时读者队列不为空),会阻塞在信号量 wDataMutex 上,读者队列中的读者全部读取结束后,最后一个读者进程执行 V(wDataMutex),唤醒刚才的写者,写者则继续开始进行写操作。

而如果是写者先到,然后读者随之而来,那么后面再来的写者程序也会应为读者的P(flag)阻塞再这个信号量之上,带读者读完后再能继续写。

从这两个方面来看确实完成了读者和写者的公平对待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

日上三杆快起床

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值