二十、经典同步问题-读者写者问题

简介: 二十、经典同步问题-读者写者问题

1、读者-写者问题描述


动机: 共享数据的访问,假设有两种类型的使用者:一种为读者,不需要修改数据;另一种为写者,其会读取和修改数据。问题的约束包括: 允许在同一时间有多个读者,但在任何时候都只有一个写者;当没有写者时,读者才能访问数据;当没有读者和写者时,写者才能访问数据;在任何时候只能有一个线程可以操作共享变量;读者优先,若在读者前面有写者在排队等待,读者可以越过写者优先进行排队。


设计算法需要用到的共享数据: 包括数据集,信号量(CountMutex)初始化为1,信号量(WriteMutex)初始化为1,整数Rcount初始化为0(记录当前读者的个数)。



2、基于信号量实现


基于读者优先和信号量的操作逻辑如下所示:

//基于信号量的writer操作逻辑
sem_wait(WriteMutex);//P操作-1,保证同一时间只有一个进程可以进行写操作
  write;
sem_post(WriteMutex);//V操作+1
//基于信号量的Reader操作逻辑
sem_wait(CountMutex);//对Rcount进行保护,进行线程互斥
  if(Rcount == 0)
    sem_wait(WriteMutex);//P操作-1,保证同一时间只有一个进程可以进行写操作
  ++Rcount;
sem_post(CountMutex);
read;
--Rcount;
sem_wait(CountMutex);//对Rcount进行保护,进行线程互斥
  if(Rcount == 0)
    sem_post(WriteMutex);//V操作+1,当最后一个读者读完之后,释放线程锁,让写者进来
sem_post(CountMutex);




3、基于管程实现


基于写者优先和管程的操作逻辑如下所示:

//基于管程的reader操作逻辑伪代码如下所示
Database::Read()
{
  Wait until no writers;//这里读者需要等待正在临界区进行操作的写者和处于等待状态的写者
  read database;
  check out - wake up waiting writers;//唤醒处于等待状态的写者
}


//基于管程的writer操作逻辑
Database::Write()
{
  Wait until no readers/writers;//这里写者需要等待正在进行操作的读者或者写者
  write database;
  check out - wake up waiting readers/writers;//唤醒处于等待状态的读者
}


//管程中的条件变量包括以下
AR=0;//正在进行读操作的reader的个数
AW=0;//正在进行写操作的writer的个数
WR=0;//等待队列中处于等待状态的reader的个数
WW=0;//等待队列中处于等待状态的writer的个数
Condition okToRead;//条件变量,表示当前是否可以进行读操作了
Condition okToWrite;//条件变量,表示当前是否可以进行写操作了
Lock lock;
Public Database::Read()
{
  //管程实现reader
  StartRead();//Wait until no writers
  read databasel
  DoneRead();//check out - wake up waiting writers
}
Private Database::StartRead()
{
  lock.Acquire();//确保只有一个进程进入到管程之中
  while(AW+WW>0) //若有正在等待或者正在进行写操作的writer
  {
    ++WR;
    okToRead.wait(&lock);
    --WR;
  }
  ++AR;
  lock.Release();
}
Private Database::DoneRead()
{
  lock.Acquire();//确保只有一个进程进入到管程之中
  --AR;
  if(AR == 0 && WW > 0)//若当前没有正在进行读操作的reader了同时有正在等待的writer
  {
    okToWrite.signal();//唤醒一个正在等待的writer
  }
  lock.Release();
}
Public Database::Write()
{
  //管程实现Writer
  StartWrite();//Wait until no readers/writers
  read databasel
  DoneWrite();//check out - wake up waiting readers/writers
}
Private Database::StartWrite()
{
  lock.Acquire();//确保只有一个进程进入到管程之中
  while(AR+AW>0) //若有正在进行读操作的reader或者正在进行写操作的writer
  {
    ++WW;
    okToWrite.wait(&lock);
    --WW;
  }
  ++AW;
  lock.Release();
}
Private Database::DoneWrite()
{
  lock.Acquire();//确保只有一个进程进入到管程之中
  --AW;
  if(WW > 0)//若当前有正在等待的writer
    okToWrite.signal();//唤醒一个正在等待的writer
  else if(WR > 0)//若当前有正在等待的reader
    okToRead.broadcast();//唤醒等待在条件变量上的所有的reader
  lock.Release();
}





相关文章
|
安全 网络协议 Java
一篇搞懂Java多线程(全网最细)(一)
一篇搞懂Java多线程(全网最细)(一)
63 0
|
存储 Java 数据库
一篇搞懂Java多线程(全网最细)(三)
一篇搞懂Java多线程(全网最细)(三)
37 0
|
Java API 调度
一篇搞懂Java多线程(全网最细)(二)
一篇搞懂Java多线程(全网最细)(二)
44 0
|
Kubernetes 监控 Linux
【k8s 系列】k8s 学习二十七 - 5,k8s 自身原理 5
我们知道容器是通过 pod 来承载的,我们在 k8s 中,服务都是跑在 pod 里面的,pod 里面可以跑 1 个容器,或者跑多个容器,那么咱们 pod 里面跑 1 个服务容器,咱真的就以为里面就只有这样个容器吗
102 0
|
Kubernetes 监控 API
【k8s 系列】k8s 学习二十七-3,k8s 自身原理 3
前面有分享到 master 主节点上的 四个组件,etcd,ApiServer,scheduler,controller manager
|
存储 Kubernetes 监控
【k8s 系列】k8s 学习二十七 - 4,k8s 自身原理 4
前面咱们分享了 mater 和 worker 节点里面都有哪些组件,他们又是各自主要负责的工作是什么,现在我们心里应该都有数了吧
140 0
|
分布式计算 JavaScript 前端开发
✨从异步讲起,『函数』和『时间』该作何关系?
✨从异步讲起,『函数』和『时间』该作何关系?
|
Linux 调度 数据库
linux系统编程(十一)线程同步(完结)(上)
linux系统编程(十一)线程同步(完结)
171 0
linux系统编程(十一)线程同步(完结)(上)
|
Linux
linux系统编程(十一)线程同步(完结)(下)
linux系统编程(十一)线程同步(完结)
196 0
linux系统编程(十一)线程同步(完结)(下)
|
机器学习/深度学习 人工智能 C++
王道考研操作系统同步与互斥(王道大题详解)(三)
王道考研操作系统同步与互斥(王道大题详解)(三)
122 0
王道考研操作系统同步与互斥(王道大题详解)(三)