zoukankan      html  css  js  c++  java
  • 进程同步中的读者写者问题

    读者写者问题-读者优先,读写公平,写者优先

    本文发表于我的个人博客:进程同步中的读者写者问题

    问题描述

    有读者和写者两组并发进程,共享一个文档,因此要求:

    • 允许多个读者同时读
    • 只允许一个写者往文件中写信息
    • 任意一个写者在完成写操作之前不允许其他读者或写者工作
    • 写者写操作前,应该让已有的读者和写者全部退出

    读者优先(写者可能饿死)

    这部分比较简单,一般课件上都会有

    使用count来记录读者的数量,mutex保护count变量, rw保证读者写者互斥访问文件

    int count = 0;
    Semaphore mutex = 1; // count 变量保护
    Semaphore rw = 1; // 文件保护
    void writer(){
      while(true){
        P(rw);
        // writing 开始写
        V(rw); // 写完了释放临界区
      }
    }
    
    void reader(){
      while(true){
        P(mutex);
        if (count == 0)	// 如果是第一个读者进入,那么开始占用文件
          P(rw);
        count++;
        V(mutex);
        // reading 开始读
        P(mutex);
        count--;
        if (count == 0) // 如果是最后一个读者离开,释放文件占用
          V(rw);
        V(mutex);
      }
    }
    

    由此可见,上面这个算法中,若源源不断地有读者进来,count会一直不为0,导致写者没有办法进入临界区,一直被P(rw)阻塞在外面卡住了。

    读写公平

    希望能读者、写者先来后到按照顺序进行,在上面的基础上,当有写进程请求访问,应当禁止后续的读进程的请求,等到已在共享文件的读进程执行完毕,立即让写进程执行。

    在没有写者的情况下,才会让读者再次运行。

    为此,在读者优先的基础上,增加一个信号量q的PV操作,对读者、写者进行约束。

    其中,P(q)相当于开始排队,V(q)相当于排队的人走了唤醒下一个队列首的人。

    int count = 0;
    Semaphore mutex = 1; // count 变量保护
    Semaphore rw = 1; // 文件保护
    Semaphore q = 1; // 使得writer和reader在同一个队列排队
    void writer(){
      while(true){
        P(q);	// 无写进程时请求进入
          P(rw);
          // writing 正在写
          V(rw); // 写完了释放临界区
        P(q);	// 恢复对共享文件的访问
      }
    }
    
    void reader(){
      while(true){
        P(q);	// 这一步使得reader有机会让给writer写 
          P(mutex);
          if (count == 0)	// 如果是第一个读者进入,那么开始占用文件
            P(rw);
          count++;
          V(mutex);
        V(q);	// 这一步唤醒被阻塞在q队列的第一个进程
        
        // reading 正在读
        
        P(mutex);
        count--;
        if (count == 0) // 如果是最后一个读者离开,释放文件占用
          V(rw);
        V(mutex);
      }
    }
    

    写者优先问题

    • 由于读-写、写-写互斥,使用信号量file控制临界区访问

      • 一群读者在读取时若有写者进来,会在队列占有quemutex,等待最后一个正在读的人离开释放file,然后立刻开始写
    • 使用一个readcount整型变量计数器,记录读者数量,用信号量rdcntmutex控制该变量的访问;writecount记录写者数量,需要信号量wrtcntmutex控制该变量访问

    • 为了实现写者优先,那么不能按照读者写者来的先后顺序排队,故设置两个队列,优先队列quemutex和读者等待队列readEntry

      • 当一个写者来时占用优先队列quemutex,一直占有到最后一个写者离开才能释放
      • 当一个读者来时放到readEntry排队,若此时前面没有其他读者,也没有写者,它才可以进到quemutex"就绪区",quemutex仅允许一个读者存在
      • 后续所有的读进程要统一放到readEntry等待。
      • 直到所有的写进程都写完了,才会唤醒quemutex中的唯一读者,该读者完成任务后,才会唤醒readEntry的第一个读者进入quemutex(即quemutex队列长度最多为2)
    int readcount = 0, writecount = 0;
    Semaphore file = 1, rdcntmutex = 1, wrtcntmutex = 1;
    Semaphore quemutex = 1, readEntry = 1;
    void Reader(){
      P(readEntry);
      	P(quemutex);			// 若有写者占用que,后续读者会被卡在外面
      		P(rdcntmutex);
      		if (readcount == 0) 
      			P(file);		// 若是第一个读者进来,则占据临界区阻止写进程写
      		readcount++;
      		V(rdcntmutex);
      	V(quemutex);
      V(readEntry);
      // 读操作不用互斥保护
      // reading operation
      // 读完了,读者走人
      P(rdcntmutex);
      	if (readcount == 1) 
      		V(file);		// 若是最后一个读者离开,则释放写进程的阻塞,允许写
      	readcount--;
      V(rdcntmutex);
    }
    
    void Writer(){
      P(wrtcntmutex);
        if (writecount == 0)
           P(quemutex);	// 一旦写者进入,则占用该优先队列
      	writecount++;
      V(wrtcntmutex);
      P(file);	// 等待现存读者读完唤醒阻塞的写者
      	// writing, 写进程需要互斥保护
      V(file);
      P(wrtcntmutex);
        if (writecount == 1)
           V(quemutex);// 若源源不断有写者进入,writecount不会为0,也不会释放
      	writecount--;		// 当最后一个写者离开,才会唤醒等在que的一个读者
      V(wrtcntmutex);
    }
    
  • 相关阅读:
    算法分析与设计C++ 并查集
    算法分析与设计 并查集
    算法分析与设计C++ 第四章:动态规划 (附4:过河卒)
    算法分析与设计C++ 2:递归:爬楼梯
    算法分析与设计C++ 1:猴子吃桃
    算法分析与设计C++ 寻找中位数 (快速排序版)
    算法设计与分析C++ 第三章: 递归与分治策略(附众数与重数 非分治实现等算法)
    算法分析与设计C++ 大整数数组汉诺塔双塔实现
    算法分析与设计C++ 第一章:递推算法(附汉诺塔递归递推实现)
    算法分析与设计C++ 第二章:STL
  • 原文地址:https://www.cnblogs.com/vanellopeblog/p/12785084.html
Copyright © 2011-2022 走看看