读者写者模型

来源:互联网 发布:玄机科技工资 知乎 编辑:程序博客网 时间:2024/05/24 02:57

一、读者写者模型

    读者:只读数据区中的数据
    写者:只往数据区中写数据
要求:
   (1)允许多个读者同时执行读操作;
   (2)不允许读者、写者同时操作;
   (3)不允许多个写者同时操作。

     我们知道在一些程序中存在读者写者问题,就是对某些资源的访问会存在两种可能的情况:一种就是写操作,写操作是可以独占资源的,也就是具有排他性;另一种情况就是读操作,在读操作中可以有多个资源并发的去访问某种资源,它的访问方式是共享的。这种模型是从对文件的读写操作中总结出的一种模型。

  1.在读者和写者的这种模型中,存在3种关系,他们是:

    1).读者和读者之间,读者与读者之间是可以并发的访问某种资源的,所以他们之间是没有关系的(共享关系)。

    2).读者和写者之间,我们知道对一个文件来说是不可以既读又写的,可能会导致数据的二义性问题。读者和写着之间是互斥和同步的关系。

    3).写着和写着之间,存在互斥的关系。

  2.在上面描述读者写者关系中提到了互斥和同步,那仫为什么要保证互斥和同步的关系呢?

    互斥:指某一种资源某一时刻只能允许一个访问者对它进行访问,具有唯一性和排他性。但是资源的互斥是无法保证访问者对资源的访问顺序的,即如果有多个访问者访问该资源时,访问是无顺序的。

    同步:同步是在互斥的基础上(大多数是互斥+同步,有的情况下只需要同步),通过一些机制实现访问者对资源的有序访问

    理解了互斥和同步让我们继续来看读者和写者问题,我们知道读者在读的过程中存在查找操作,费时较长,如果给读者加锁会降低这种模型的实现效率,可以总结为读者写者模型就是一种多读少写的情况,为了解决这种情况,引入了读者锁的概念。


二、自旋锁与互斥锁:
自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁。
读写锁实际上是一把自旋锁。
未加读写锁之前:
参考代码:

#include<stdlib.h>#include<stdio.h>#include<pthread.h>int value=0;void* writer(void *arg){  while(1)  {    sleep(2);    value++;  } return (void*)0;}void* reader(void *arg){  while(1)  {    printf("write value:%d\n",value);  }  return (void*)0;}int main(){  pthread_t tid1;  pthread_t tid2;  pthread_create(&tid1,NULL,writer,NULL);  pthread_create(&tid2,NULL,reader,NULL);  pthread_join(tid1,NULL);  pthread_join(tid2,NULL);  return 0;}

由于读的几率比较高,所以数据得不到及时更新。如下:
运行结果:

这里写图片描述
加了读写锁之后,如果新读者到:
①无读者、写者,新读者可以读;
②有写者等待,但有其它读者正在读,则新读者也可以读;
③有写者写,新读者等待。
如果新写者到:
①无读者,新写者可以写;
②有读者,新写者等待;
③有其它写者,新写者等待。


#include<stdlib.h>#include<stdio.h>#include<pthread.h>pthread_rwlock_t rwlock; int value=0;void* writer(void *arg){  while(1)  {      sleep(1);    if(pthread_rwlock_wrlock(&rwlock)!=0)    {      printf("reader is reading\n");    }    value++;    printf("write value:%d\n",value);    pthread_rwlock_unlock(&rwlock);  } return (void*)0;}void* reader(void *arg){  while(1)  {      sleep(1);    if(pthread_rwlock_rdlock(&rwlock)!=0)    {      printf("writer is writing\n");    }    printf("read  value:%d\n",value);    pthread_rwlock_unlock(&rwlock);  }  return (void*)0;}int main(){  pthread_t tid1;  pthread_t tid2;  pthread_rwlock_init(&rwlock,NULL);  pthread_create(&tid1,NULL,writer,NULL);  pthread_create(&tid2,NULL,reader,NULL);  pthread_rwlock_destroy(&rwlock);  pthread_join(tid1,NULL);  pthread_join(tid2,NULL);  return 0;}

运行结果:



读者写者模型和生产者消费者模型区别
读者写者模型中写者写入数据,但读者并不会消费数据,只会访问。其中的写操作是排他的(排斥读者和其他写者),读操作是共享的。
生产者消费者模型中生产者生产产品,消费者不断的消费产品,产品的数量在不断的下降。如果此时临界区无数据时,消费者被阻塞,直至生产者生产出数据时来唤醒消费者,若临界区资源满了时,生产者被阻塞,在消费者消费后唤醒生产者


、读者写者模型代码
        读者写者访问一块共享的数据区域,读者对共享资源进行读访问,写者对共享内存进行写操作。在多处理器系统中,运去多个读者同时访问共享内存,而写者是排他性的,每次只能有一个写者去写入数据。在使用读写锁时,一个读写锁只能同时一个读者和多个写者,但不能同时既有读者又有写者。
公平情况的读者写者代码:
这里写图片描述
这里写图片描述

运行结果
这里写图片描述 


此时读者和写者有相同的机会运行,是公平情况。
读者写者有三类情况:读者优先,写者优先,公平情况
1、读者优先
读者先来读取数据(其他的读者也可以来读取数据),此时写者等待,也就是说读者可以插写者的队,这是读者优先的关键点,只有当读者为0,写者才能来写入数据。
      *写者要有一个互斥信号量 writeMutex=1,因为写者一次只能一个来写数据 
      * 对读者要有一个记录数目的 int 变量,readcount=0,一个互斥信号量readMutex = 1,保证多个读者来的时候,能似的 readcount 互斥的变化,也就是不被混乱的计数。
2、写者优先
类似读者优先算法,同理,这里是写者可以插队,多用一个 readable 信号量,控制写者可以优先于读者进入临界区,一个整数 writecount 统计写者,而 wmutex 控制写者互质访问 writecount
3、公平情况
读者想进的时候,有写者正在写(或者正在等待写),读者就不能进(读者等待),只有写者走了,读者才能进。和一相比,需要多一个信号量 wmutex=1,表示是否存在写者正在写或者等待写,如果存在,读者就等待,读者不能插队了。


原创粉丝点击