操作系统实验之多线程操作之读者优先与写者优先第二版

简介: 操作系统实验之多线程操作之读者优先与写者优先第二版

之前作者做的那个实验有误,希望大家见谅,在室友的质疑之后觉得的确存在着很大的问题,所以自己今天又把一些逻辑上的漏洞又重新完善了一下。其实主要的逻辑漏洞又两个方面

第一就是,最后没有在总时间内到达的线程,最终是不能直接按照到达时间排序完之后的顺序直接打印的,而应该是每一次,将一个轮回里面能够到达的线程按照那样的检查机构打印出来后,剩下的没有到达的线程也应该是重新打入那个队列,然后在按照之前的规则继续打印,直到最后的队列中再也不存在元素,说明所有的线程都已经执行完毕

第二个就是之前的一个总时间计算问题,作者之后发现有一部分的总时间计算是存在问题的,下面作者会通过一个图来让读者们理解:


20181126103806552.png


这样所有情况的图基本上都完成了。作者之前的第一版本,sum都考虑到了,但是在写者优先中漏了一种,就想着顺便把之前的图也给读者们讲一下吧。

接下来,是源代码。重点就是作者并不是在主函数中继续操作,而是通过将之前的那两种方法封装起来,通过队列是否为空来控制执行的过程


import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
public class 多线程编程第二版 {
  public static Queue<tcb>queue=new PriorityQueue<tcb>();
  public static List<tcb>list=new ArrayList<>();
  public static int sum;
  public static void duzhe()
  {
    //System.out.println("重新开始的队列");
    tcb tcb2=queue.poll();
    System.out.println(tcb2.id+" "+tcb2.name+"结束线程");
    int n=queue.size();
    sum=tcb2.starttime+tcb2.lasttime;
    if(tcb2.name.equals("R"))//在第一个线程是读的情况下
    {
      for(int i=0;i<n;i++)//开始查询在第一个读线程执行的过程中是否有别的读线程进来,
      {
        tcb tcb3=queue.poll();
        if(tcb3.name.equals("R"))//那么可以直接并发的执行,
        {
          if(tcb3.starttime<=sum)
          {
            System.out.println(tcb3.id+" "+tcb3.name+"结束线程"); 
            if(sum<(tcb3.starttime+tcb3.lasttime))
              sum=tcb3.starttime+tcb3.lasttime;
          }
          else //如果不在时间段内到达,就存入列表中,因为一开始的队列就已经按到达时间进行排序了
            list.add(tcb3);
        }
        else {//因为读线程正在执行,所以写线程不能执行,也像那些没有在规定时间内到达的读线程一样存入列表中
          list.add(tcb3);
        }
      }
      for(int i=0;i<list.size();i++)
        queue.add(list.get(i));
      list.clear();
    }
    else//首个线程是写线程
    {
      a:for(int i=0;i<n;i++)//这里的重点是找出第一个读线程,因为只有读线程是存在这并发执行的情况的,其他的情况都是按照时间进行单向操作的
      {
        tcb tcb3=queue.poll();
        if(tcb3.name.equals("W"))//写线程是单向执行的所以可以直接进行操作
        {
          System.out.println(tcb3.id+" "+tcb3.name+"结束线程");
          if(sum>tcb3.starttime)
            sum+=tcb3.lasttime;
          else 
            sum=tcb3.starttime+tcb3.lasttime;
        }
        if(tcb3.name.equals("R"))//当找到第一个写线程是退出该循环,但是这个写线程是可以直接进行操作的
        {
          System.out.println(tcb3.id+" "+tcb3.name+"结束线程");
          if(sum>tcb3.starttime)
            sum+=tcb3.lasttime;
          else 
            sum=tcb3.starttime+tcb3.lasttime;
          break a;
        }
      }
        int length=queue.size();
        for(int i=0;i<length;i++)//这时候进行的操作仍就是类似于上面的把能够并发执行的线程都直接打印出来,不能并发执行的线程都存入列表中
        {
          tcb tcb3=queue.poll();
          if(tcb3.name.equals("R"))
          {
           if(tcb3.starttime<=sum)
           {
            System.out.println(tcb3.id+" "+tcb3.name+"结束线程"); 
            if(sum<(tcb3.starttime+tcb3.lasttime))
              sum=tcb3.starttime+tcb3.lasttime;
           }
           else
            list.add(tcb3);
          }
          else 
          {
           list.add(tcb3);
          }
        }
        for(int i=0;i<list.size();i++)
        queue.add(list.get(i));
      list.clear();
    }
  }
  public static void xiezhe()
  {
    //System.out.println("开始新的队列");
    tcb tcb2=queue.poll();
    System.out.println(tcb2.id+" "+tcb2.name+"结束线程");
    sum=tcb2.starttime+tcb2.lasttime;
    int n=queue.size();
    if(tcb2.name.equals("W"))//写着优先中如果第一个线程是写线程的话,那么操作就和上述读者优先的操作有点类似
    {
      for(int i=0;i<n;i++)
      {
        tcb tcb3=queue.poll();
        if(tcb3.name.equals("W"))//这里可以直接打印写线程是因为写线程的优先级比读线程的优先级高
                               //而且这里的打印并不代表是并发的执行多个写线程,而是单向的一个一个执行写线程
        {
          if(tcb3.starttime<=sum)
          {
            System.out.println(tcb3.id+" "+tcb3.name+"结束线程"); 
              sum+=tcb3.lasttime;
          }
          else                  //将不再能到达的范围内的写线程存入列表中
            list.add(tcb3);
        }
          else 
          { 
           list.add(tcb3);
          }
      }
      for(int i=0;i<list.size();i++)
        queue.add(list.get(i));
      list.clear();
    }
    else//这里的可以和上面的读者优先的第二种情况进行类比
    {
      a:for(int i=0;i<n;i++)
      {
        tcb tcb3=queue.poll();
        if (tcb3.name.equals("W")) 
        {
          System.out.println(tcb3.id+" "+tcb3.name+"结束线程");
          //sum+=tcb3.lasttime;
          if(sum>tcb3.starttime)
            sum+=tcb3.lasttime;
          else 
            sum=tcb3.starttime+tcb3.lasttime;
          break a;
        }
        else
        {
          if(tcb3.starttime<=sum)
          {
            System.out.println(tcb3.id+" "+tcb3.name+"结束线程"); 
            if(sum<(tcb3.starttime+tcb3.lasttime))
              sum=tcb3.starttime+tcb3.lasttime;               
          }
        }
      }
    int length=queue.size();
    for(int i=0;i<length;i++)
    {
      tcb tcb3=queue.poll();
      if(tcb3.name.equals("W"))
      {
        if(tcb3.starttime<=sum)
        {
          System.out.println(tcb3.id+" "+tcb3.name+"结束线程"); 
            sum+=tcb3.lasttime;
        }
        else
          list.add(tcb3);
      }
        else 
        { 
         list.add(tcb3);
        }
    }
    for(int i=0;i<list.size();i++)
      queue.add(list.get(i));
    list.clear();
    }
  }
  public static void main(String[] args) {
    Scanner sc=new Scanner(System.in);
    int n=sc.nextInt();
    tcb[]tcb1=new tcb[n];
    System.out.println("线程的id号     名称       开始时间     持续时间");
    for(int i=0;i<n;i++)
    {
      tcb1[i]=new tcb();
      tcb1[i].id=sc.nextInt();
      //System.out.println("第"+(i+1)+"个线程的名称");
      tcb1[i].name=sc.next();
      //System.out.println("第"+(i+1)+"个线程的开始时间");
      tcb1[i].starttime=sc.nextInt();
      //System.out.println("第"+(i+1)+"个线程的持续时间");
      tcb1[i].lasttime=sc.nextInt();
    }
    System.out.println("信号量机制如下:");
    System.out.println("1.读者优先");
    System.out.println("2.写者优先");
    System.out.println("请选择机制的编号:");
    int m=sc.nextInt();
    while(m>2||m<1)
    {
      System.out.println("选择方式不存在,请重新选择机制编号:");
      m=sc.nextInt();
    }
    if(m==1)//读者优先
    { 
      sum=0;
      queue=new PriorityQueue<tcb>(compare1);
      for(int i=0;i<n;i++)
        queue.add(tcb1[i]);
      while(!queue.isEmpty())
      {
        duzhe();
      }
    }
    else if(m==2)//写者优先
    {
      sum=0;
      queue=new PriorityQueue<tcb>(compare1);
      for(int i=0;i<n;i++)
        queue.add(tcb1[i]);
      while(!queue.isEmpty())
      {
        xiezhe();
      }
    }
  }
  static Comparator<tcb>compare1=new Comparator<tcb>() {//按到达时间排序
    @Override
    public int compare(tcb o1, tcb o2) {
      // TODO Auto-generated method stub
      return o1.starttime-o2.starttime;
    }
  };
  static class tcb
  {
    int id;
    String name;
    int starttime;
    int lasttime;
    public tcb() {
      // TODO Auto-generated constructor stub
    }
  }
}


最后作者提供了两个用例测试了两个版本的答案,最后的确证明逻辑上是存在漏洞的,下面分别是两个代码执行的结果图

首先是读者优先

正确的答案:


20181126104506528.png


错误的答案演示:


20181126104551444.png


之后是写者优先的演示

正确的答案演示:


20181126104712873.png


错误的答案演示:


20181126104826108.png


作者很菜,如果还有错误,还望大家指正!!!

相关文章
|
1月前
|
调度 开发者 Python
深入浅出操作系统:进程与线程的奥秘
在数字世界的底层,操作系统扮演着不可或缺的角色。它如同一位高效的管家,协调和控制着计算机硬件与软件资源。本文将拨开迷雾,深入探索操作系统中两个核心概念——进程与线程。我们将从它们的诞生谈起,逐步剖析它们的本质、区别以及如何影响我们日常使用的应用程序性能。通过简单的比喻,我们将理解这些看似抽象的概念,并学会如何在编程实践中高效利用进程与线程。准备好跟随我一起,揭开操作系统的神秘面纱,让我们的代码运行得更加流畅吧!
|
2月前
|
算法
数据结构实验之操作系统打印机管理器问题
本实验旨在通过实现操作系统中的打印机管理器问题,掌握队列的基本操作如入队、出队等,利用队列的先进先出特性解决先申请先打印的问题。实验包括队列的初始化、入队、出队、打印队列内容等功能,并通过菜单式界面进行交互。实验结果显示基本功能可正常执行,但在连续操作时存在执行失败的情况,需进一步优化。
48 4
|
5月前
|
UED 开发者 Python
探索操作系统的心脏:理解进程与线程
【8月更文挑战第31天】在数字世界的海洋中,操作系统犹如一艘巨轮,其稳定航行依赖于精密的进程与线程机制。本文将揭开这一机制的神秘面纱,通过深入浅出的语言和直观的代码示例,引领读者从理论到实践,体验进程与线程的魅力。我们将从基础概念出发,逐步深入到它们之间的联系与区别,最后探讨如何在编程实践中高效运用这些知识。无论你是初学者还是有经验的开发者,这篇文章都将为你的技术之旅增添新的航标。
|
1月前
|
算法 调度 开发者
深入理解操作系统:进程与线程的管理
在数字世界的复杂编织中,操作系统如同一位精明的指挥家,协调着每一个音符的奏响。本篇文章将带领读者穿越操作系统的幕后,探索进程与线程管理的奥秘。从进程的诞生到线程的舞蹈,我们将一起见证这场微观世界的华丽变奏。通过深入浅出的解释和生动的比喻,本文旨在揭示操作系统如何高效地处理多任务,确保系统的稳定性和效率。让我们一起跟随代码的步伐,走进操作系统的内心世界。
|
2月前
|
Linux 调度 C语言
深入理解操作系统:进程和线程的管理
【10月更文挑战第32天】本文旨在通过浅显易懂的语言和实际代码示例,带领读者探索操作系统中进程与线程的奥秘。我们将从基础知识出发,逐步深入到它们在操作系统中的实现和管理机制,最终通过实践加深对这一核心概念的理解。无论你是编程新手还是希望复习相关知识的资深开发者,这篇文章都将为你提供有价值的见解。
|
2月前
深入理解操作系统:进程与线程的管理
【10月更文挑战第30天】操作系统是计算机系统的核心,它负责管理计算机硬件资源,为应用程序提供基础服务。本文将深入探讨操作系统中进程和线程的概念、区别以及它们在资源管理中的作用。通过本文的学习,读者将能够更好地理解操作系统的工作原理,并掌握进程和线程的管理技巧。
46 2
|
2月前
|
调度 Python
深入浅出操作系统:进程与线程的奥秘
【10月更文挑战第28天】在数字世界的幕后,操作系统悄无声息地扮演着关键角色。本文将拨开迷雾,深入探讨操作系统中的两个基本概念——进程和线程。我们将通过生动的比喻和直观的解释,揭示它们之间的差异与联系,并展示如何在实际应用中灵活运用这些知识。准备好了吗?让我们开始这段揭秘之旅!
|
4月前
|
存储 消息中间件 资源调度
「offer来了」进程线程有啥关系?10个知识点带你巩固操作系统基础知识
该文章总结了操作系统基础知识中的十个关键知识点,涵盖了进程与线程的概念及区别、进程间通信方式、线程同步机制、死锁现象及其预防方法、进程状态等内容,并通过具体实例帮助理解这些概念。
「offer来了」进程线程有啥关系?10个知识点带你巩固操作系统基础知识
|
3月前
|
算法 安全 调度
深入理解操作系统:进程与线程的管理
【10月更文挑战第9天】在数字世界的心脏跳动着的,不是别的,正是操作系统。它如同一位无形的指挥家,协调着硬件与软件的和谐合作。本文将揭开操作系统中进程与线程管理的神秘面纱,通过浅显易懂的语言和生动的比喻,带你走进这一复杂而又精妙的世界。我们将从进程的诞生讲起,探索线程的微妙关系,直至深入内核,理解调度算法的智慧。让我们一起跟随代码的脚步,解锁操作系统的更多秘密。
46 1
|
2月前
|
Linux 调度
探索操作系统核心:进程与线程管理
【10月更文挑战第24天】在数字世界的心脏,操作系统扮演着至关重要的角色。它不仅是计算机硬件与软件之间的桥梁,更是管理和调度资源的大管家。本文将深入探讨操作系统的两大基石——进程与线程,揭示它们如何协同工作以确保系统运行得井井有条。通过深入浅出的解释和直观的代码示例,我们将一起解锁操作系统的管理奥秘,理解其对计算任务高效执行的影响。