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

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

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





相关文章
|
7天前
|
数据采集 Java Linux
面试大神教你:如何巧妙回答线程优先级这个经典考题?
大家好,我是小米。本文通过故事讲解Java面试中常见的线程优先级问题。小明和小华的故事帮助理解线程优先级:高优先级线程更可能被调度执行,但并非越高越好。实际开发需权衡业务需求,合理设置优先级。掌握线程优先级不仅能写出高效代码,还能在面试中脱颖而出。最后,小张因深入分析成功拿下Offer。希望这篇文章能助你在面试中游刃有余!
29 4
面试大神教你:如何巧妙回答线程优先级这个经典考题?
|
8月前
|
Java C++
关于《Java并发编程之线程池十八问》的补充内容
【6月更文挑战第6天】关于《Java并发编程之线程池十八问》的补充内容
61 5
|
5月前
|
存储 消息中间件 资源调度
「offer来了」进程线程有啥关系?10个知识点带你巩固操作系统基础知识
该文章总结了操作系统基础知识中的十个关键知识点,涵盖了进程与线程的概念及区别、进程间通信方式、线程同步机制、死锁现象及其预防方法、进程状态等内容,并通过具体实例帮助理解这些概念。
「offer来了」进程线程有啥关系?10个知识点带你巩固操作系统基础知识
|
安全 网络协议 Java
一篇搞懂Java多线程(全网最细)(一)
一篇搞懂Java多线程(全网最细)(一)
74 0
|
Java API 调度
一篇搞懂Java多线程(全网最细)(二)
一篇搞懂Java多线程(全网最细)(二)
56 0
|
存储 Java 数据库
一篇搞懂Java多线程(全网最细)(三)
一篇搞懂Java多线程(全网最细)(三)
57 0
二十一、经典同步问题-哲学家就餐问题
二十一、经典同步问题-哲学家就餐问题
二十一、经典同步问题-哲学家就餐问题
|
Linux
linux系统编程(十一)线程同步(完结)(下)
linux系统编程(十一)线程同步(完结)
222 0
linux系统编程(十一)线程同步(完结)(下)
|
Linux 调度 数据库
linux系统编程(十一)线程同步(完结)(上)
linux系统编程(十一)线程同步(完结)
181 0
linux系统编程(十一)线程同步(完结)(上)
|
存储 算法
【数据结构与算法】第七章:队列的表示与操作实现
前面两章重点介绍了栈的表示与实现,本章将详细解释队列的表示与实现,以及相关的基本操作。
356 0