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

时间:2022-07-23
本文章向大家介绍操作系统实验多线程编程中的读者优先和写者优先,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
  • 首先需要理解在线程无论是读者优先还是写者优先都需要尊重两种约束,就是读写与写写操作是无法同时进行的,能同时进行就只能是读读操作
  • 其次需要理解读者优先于写者优先的概念
  • 首先说的是读者优先
  • 许多人对读者优先的概念可能就直接是读者的优先权最大,这样的想法是错误的,假设已经在进行一个写线程了,那么这时候来的读线程是无法让写线程退出,在执行读线程的。
  • 只存在这说有一个读线程在执行,这时候又来了一个读线程,这时候后来的那个读线程是能够并发的执行的,但假设在这个读线程之后又来了一个写线程,
  • 这时候的写线程需要等到所有在这段时间内都到达的读线程都执行完了之后才能执行
  • 再来说写者优先
  • 写者优先就不一样了,他的优先的确比读线程要高,就算有一个读线程正在执行,但是写线程在这过程中来了,
  • 那么那个读线程还是需要先退出来,先在队列中等待,等到写线程结束以后再进行读线程
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
		}
		
	}
}

如有错误,请指正