操作系统实验多线程编程中的读者优先和写者优先

简介: 操作系统实验多线程编程中的读者优先和写者优先

首先需要理解在线程无论是读者优先还是写者优先都需要尊重两种约束,就是读写与写写操作是无法同时进行的,能同时进行就只能是读读操作

其次需要理解读者优先于写者优先的概念

首先说的是读者优先

许多人对读者优先的概念可能就直接是读者的优先权最大,这样的想法是错误的,假设已经在进行一个写线程了,那么这时候来的读线程是无法让写线程退出,在执行读线程的。

只存在这说有一个读线程在执行,这时候又来了一个读线程,这时候后来的那个读线程是能够并发的执行的,但假设在这个读线程之后又来了一个写线程,

这时候的写线程需要等到所有在这段时间内都到达的读线程都执行完了之后才能执行

再来说写者优先

写者优先就不一样了,他的优先的确比读线程要高,就算有一个读线程正在执行,但是写线程在这过程中来了,

那么那个读线程还是需要先退出来,先在队列中等待,等到写线程结束以后再进行读线程


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 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)//读者优先
    { 
      int sum=0;
      Queue<tcb>list=new PriorityQueue<>(compare1);
      List<tcb>list1=new ArrayList<>();
      for(int i=0;i<n;i++)
        list.add(tcb1[i]);
      tcb tcb2=list.poll();
      System.out.println(tcb2.id+" "+tcb2.name+"结束线程");
      sum+=tcb2.starttime+tcb2.lasttime;
      if(tcb2.name.equals("R"))//在第一个线程是读的情况下
      {
        for(int i=0;i<n-1;i++)//开始查询在第一个读线程执行的过程中是否有别的读线程进来,
        {
          tcb tcb3=list.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 //如果不在时间段内到达,就存入列表中,因为一开始的队列就已经按到达时间进行排序了
              list1.add(tcb3);
          }
          else {//因为读线程正在执行,所以写线程不能执行,也像那些没有在规定时间内到达的读线程一样存入列表中
            list1.add(tcb3);
          }
        }
        for(int i=0;i<list1.size();i++)//最后打印列表中的数据,能通过列表打印,是因为,
                                     //这时候能够并发执行的都已经并发执行结束了,所以剩下的都是,按照时间单向执行的了
          System.out.println(list1.get(i).id+" "+list1.get(i).name+"结束线程");
      }
      else//首个线程是写线程
      {
        a:for(int i=0;i<n-1;i++)//这里的重点是找出第一个读线程,因为只有读线程是存在这并发执行的情况的,其他的情况都是按照时间进行单向操作的
        {
          tcb tcb3=list.poll();
          if(tcb3.name.equals("W"))//写线程是单向执行的所以可以直接进行操作
          {
            System.out.println(tcb3.id+" "+tcb3.name+"结束线程");
            sum+=tcb3.lasttime;
          }
          if(tcb3.name.equals("R"))//当找到第一个写线程是退出该循环,但是这个写线程是可以直接进行操作的
          {
            System.out.println(tcb3.id+" "+tcb3.name+"结束线程");
            sum+=tcb3.lasttime;
            break a;
          }
        }
      int length=list.size();
      for(int i=0;i<length;i++)//这时候进行的操作仍就是类似于上面的把能够并发执行的线程都直接打印出来,不能并发执行的线程都存入列表中
      {
        tcb tcb3=list.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
            list1.add(tcb3);
        }
        else {
          list1.add(tcb3);
        }
      }
      for(int i=0;i<list1.size();i++)
        System.out.println(list1.get(i).id+" "+list1.get(i).name+"结束线程");
      }
    }
    else if(m==2)//写者优先
    {
      int sum=0;
      Queue<tcb>list=new PriorityQueue<>(compare1);
      List<tcb>list1=new ArrayList<>();
      for(int i=0;i<n;i++)
        list.add(tcb1[i]);
      tcb tcb2=list.poll();
      System.out.println(tcb2.id+" "+tcb2.name+"结束线程");
      sum+=tcb2.starttime+tcb2.lasttime;
      if(tcb2.name.equals("W"))//写着优先中如果第一个线程是写线程的话,那么操作就和上述读者优先的操作有点类似
      {
        for(int i=0;i<n-1;i++)
        {
          tcb tcb3=list.poll();
          if(tcb3.name.equals("W"))//这里可以直接打印写线程是因为写线程的优先级比读线程的优先级高
                                 //而且这里的打印并不代表是并发的执行多个写线程,而是单向的一个一个执行写线程
          {
            if(tcb3.starttime<=sum)
            {
              System.out.println(tcb3.id+" "+tcb3.name+"结束线程"); 
                sum+=tcb3.lasttime;
            }
            else                  //将不再能到达的范围内的写线程存入列表中
              list1.add(tcb3);
          }
            else 
            { 
             list1.add(tcb3);
            }
        }
        for(int i=0;i<list1.size();i++)//最后将所有不能并发(只能说是类似)因为本质上还是单向的,打印出来
          System.out.println(list1.get(i).id+" "+list1.get(i).name+"结束线程");
      }
      else//这里的可以和上面的读者优先的第二种情况进行类比
      {
        a:for(int i=0;i<n-1;i++)
        {
          tcb tcb3=list.poll();
          if (tcb3.name.equals("W")) 
          {
            System.out.println(tcb3.id+" "+tcb3.name+"结束线程");
            sum+=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=list.size();
      for(int i=0;i<length;i++)
      {
        tcb tcb3=list.poll();
        if(tcb3.name.equals("W"))
        {
          if(tcb3.starttime<=sum)
          {
            System.out.println(tcb3.id+" "+tcb3.name+"结束线程"); 
              sum+=tcb3.lasttime;
          }
          else
            list1.add(tcb3);
        }
          else 
          { 
           list1.add(tcb3);
          }
      }
      for(int i=0;i<list1.size();i++)
        System.out.println(list1.get(i).id+" "+list1.get(i).name+"结束线程");
      }
    }
  }
  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 Comparator<tcb>compare2=new Comparator<tcb>() {//写者优先排序
    @Override
    public int compare(tcb o1, tcb o2) {
      // TODO Auto-generated method stub
      return 0;
    }
  };*/
  static class tcb
  {
    int id;
    String name;
    int starttime;
    int lasttime;
    public tcb() {
      // TODO Auto-generated constructor stub
    }
  }
}

如有错误,请指正

相关文章
|
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天】在数字世界的心脏,操作系统扮演着至关重要的角色。它不仅是计算机硬件与软件之间的桥梁,更是管理和调度资源的大管家。本文将深入探讨操作系统的两大基石——进程与线程,揭示它们如何协同工作以确保系统运行得井井有条。通过深入浅出的解释和直观的代码示例,我们将一起解锁操作系统的管理奥秘,理解其对计算任务高效执行的影响。