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

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

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();
}





相关文章
|
12月前
|
分布式计算 JavaScript 前端开发
✨从异步讲起,『函数』和『时间』该作何关系?
✨从异步讲起,『函数』和『时间』该作何关系?
|
Linux 调度 数据库
linux系统编程(十一)线程同步(完结)(上)
linux系统编程(十一)线程同步(完结)
146 0
linux系统编程(十一)线程同步(完结)(上)
|
Linux
linux系统编程(十一)线程同步(完结)(下)
linux系统编程(十一)线程同步(完结)
152 0
linux系统编程(十一)线程同步(完结)(下)
|
SQL 缓存 Java
Android多线程编程__同步(下)
在多线程应用中,两个或两个以上的线程需要共享对同一个数据的存取。
95 0
|
存储 缓存 Java
Android多线程编程__同步(上)
在多线程应用中,两个或两个以上的线程需要共享对同一个数据的存取。
121 0
Android多线程编程__同步(上)
|
存储 SQL 安全
搞定|通过实际案例搞懂多任务线程
搞定|通过实际案例搞懂多任务线程
搞定|通过实际案例搞懂多任务线程
|
存储 安全 Java
(十六)关于Java多线程锁的升级原理,这篇文章会让你另有收获
对象头用于存储对象的元数据信息,包括运行时数据和类型指针、实例数据存储的是真正有效数据、对齐填充主要补充字节,使得内存所占字节能被8整除。
|
安全 C++
模拟生产者-消费者问题和读者-写者问题
模拟生产者-消费者问题和读者-写者问题
318 0
模拟生产者-消费者问题和读者-写者问题
|
缓存
认真阅读完这篇文章熟练掌握多线程常见锁的基本用法
认真阅读完这篇文章熟练掌握多线程常见锁的基本用法
113 0
认真阅读完这篇文章熟练掌握多线程常见锁的基本用法
|
Java 开发者
同步问题引出|学习笔记
快速学习 同步问题引出
同步问题引出|学习笔记