操作系统之多线程编程—读者优先/写者优先详解
操作系統之進程調度——優先權法和輪轉法(附上樣例講解)
操作系統之銀行家算法—詳解流程及案例數據
操作系統之多線程編程—讀者優先/寫者優先詳解
操作系統之存儲管理——FIFO算法和LRU算法
操作系統之磁盤調度——SCAN實例講解
要求
一、實驗目的
1、熟悉多線程編程
2、熟悉使用信號量機制解決進程同步問題
二、實驗內容
創建一個包含n 個線程的控制臺進程。用這n 個線程來表示n個讀者或寫者。每個線程按相應測試數據文件的要求,進行讀寫操作。請用信號量機制分別實現讀者優先和寫者優先的讀者-寫者問題。
讀者優先:如果一個讀者申請進行讀操作時已有另一讀者正在進行讀操作,則該讀者可直接開始讀操作。
寫者優先:如果一個讀者申請進行讀操作時已有另一寫者在等待訪問共享資源,則該讀者必須等到沒有寫者處于等待狀態后才能開始讀操作。
三、實驗條件
1、為每個學生提供一臺具有WINDOWS 2000/NT/XP操作系統的計算機;
2、實驗機器要求安裝Visual C 6.0編程平臺;
3、實驗要求一人一機。
四、 運行結果顯示要求
1、要求在每個線程創建、發出讀寫操作申請、開始讀寫操作和結束讀寫操作時分別顯示一行提示信息,以確信所有處理都遵守相應的讀寫操作限制。
2、測試數據文件格式:測試數據文件包括n 行測試數據,分別描述創建的n 個線程是讀者還是寫者,以及讀寫操作的開始時間和持續時間。每行測試數據包括四個字段,各字段間用空格分隔。第一字段為一個正整數,表示線程序號。第二字段表示相應線程角色,R 表示讀者是,W 表示寫者。第三字段為一個正數,表示讀寫操作的開始時間。線程創建后,延時相應時間(單位為秒)后發出對共享資源的讀寫申請。第四字段為一個正數,表示讀寫操作的持續時間。當線程讀寫申請成功后,開始對共享資源的讀寫操作,該操作持續相應時間后結束,并釋放共享資源。下面是一個測試數據文件的例子:
1 R 3 5
2 W 4 5
3 R 5 2
4 R 6 5
理解
上面是實驗要求。下面講講自己的體會:
- 首先要明白在多線程編程中的互斥關系——讀寫互斥,寫寫互斥。兩個優先方式都遵從這個出發點。
- 在滿足以上的條件下,進來的線程都好像是在排隊,然后看當前誰優先。
- 自己如果是優先的,那么可以直接插隊。再考慮正在執行的是否和自己阻塞,如果正在執行的和自己阻塞,那自己也得排隊,只不過排在前面。(類似寫者優先的寫寫線程)如果正在執行的和自己不是阻塞的,那么自己就可以直接進去執行(讀者優先的讀讀進程)。
- 如果自己不是優先的,那么自己只能老老實實的排隊,就算自己前面有和自己不互斥的線程執行也不行。類似寫者優先的(讀線程在執行,新的寫進程等待資源,更新的讀線程只能等寫進程釋放,如果有新的寫進程進來,還可以插隊,——他只能等待隊列中所有在等待的寫進程釋放完畢再執行自己。)
- 對于讀者優先 :
讀者就是優先的。假設a,b都是同時請求,但是a是讀者那么a優先使用資源,還有一點很重要的就是讀者優先的讀者可以并行執行。而寫著只能單線程執行。在執行過程中,只要阻塞的寫者在等待過程中有新的讀者進來那么他要等待所有讀者完成才能自己釋放自己。
- 對于寫者優先:
無疑所有寫的操作是優先的,這個過程可能會產生大量阻塞,因為相對較快(本來可以并行的讀者被大量阻塞)。如果資源中沒有寫者那么讀者依然可以并行,但是一旦出現寫者在等待讀者資源,那么新的讀者就不能在并行執行,要等待所有寫者執行完畢才可執行讀者。
對于多線程編程的注意點有:
我的大體思路(水平有限,不一定很準確):
代碼
下面附上我的ac代碼
package 實驗;import java.util.Comparator; import java.util.PriorityQueue; import java.util.Queue; import java.util.Scanner;public class morethread {static Scanner sc=new Scanner(System.in);static Queue<thread>q1;static Queue<thread>end;static thread thread[];static int time=0;private static void threadcreate(int n) {//創建線程thread=new thread[n];for(int i=0;i<n;i++) {System.out.println("請輸入線程"+(i+1)+"的相關屬性(id,r/w,intime,timelong)");int id=sc.nextInt();String type=sc.next();int start=sc.nextInt();int chixu=sc.nextInt();thread [i]=new thread(id, type, start, chixu);System.out.println("線程"+id+" 操作:"+type+" 開始時間:"+start+" 持續時間:"+chixu);}}private static void writerthread(int n) {//寫者優先// TODO 自動生成的方法存根q1=new PriorityQueue<thread>(comstart2);end=new PriorityQueue<thread>(comend);for(int i=0;i<n;i++){q1.add(thread[i]);end.add(thread[i]);}int timeend=-1;//讀結束的時間最晚int writendtime=0;//寫操作結束的時間thread start=q1.peek();thread finish=end.peek();boolean iswait=false;//是否有write操作在等待while(!q1.isEmpty()||!end.isEmpty()){if(!q1.isEmpty()) {start=q1.peek();}if(!end.isEmpty()) {finish=end.peek();}if(start.starttime<(finish.starttime+finish.totaltime)&&!q1.isEmpty())//可以開始讀寫操作{thread team=q1.poll();if(team.type.equals("w"))//寫操作{if(team.starttime>=writendtime)//沒有寫操作在前面{if(team.starttime<timeend)//需要等待 更改改點信息重新pull入隊列{iswait=true;//聲明之后其他讀操作就不能再直接進行team.starttime=timeend;q1.add(team);end.remove(team);end.add(team);}else {//不需要等待,直接開始System.out.println("線程"+team.id+" 開始:"+team.type+"操作 時間:"+team.starttime+" 結束時間"+(team.starttime+team.totaltime));writendtime=team.starttime+team.totaltime;//更新寫操作的結束時間iswait=false;//更新等待點}}else//有正在進行的操作,需要等待{iswait=true;team.starttime=writendtime;q1.add(team);end.remove(team);end.add(team);//移除然后增加才可以重新排序}}else//讀操作{if(iswait){//不清楚他在等待讀操作還是寫操作,反正它一定不能在下面兩個操作之前完成,所以更新節點道值最大的int time2=timeend;if(time2<writendtime)time2=writendtime;team.starttime=time2;q1.add(team);end.remove(team);end.add(team);}else//沒有等待點{if(team.starttime<writendtime)//有寫操作,讀需要等待 將這個點從新弄道隊列里面{team.starttime=writendtime;q1.add(team);end.remove(team);end.add(team);}else//可以釋放了{System.out.println("線程"+team.id+" 開始:"+team.type+"操作 時間:"+team.starttime+" 結束時間"+(team.starttime+team.totaltime)); if(team.starttime+team.totaltime>timeend)//如果可以更新時間{timeend=team.starttime+team.totaltime;}}}} } else{thread team=end.poll();System.out.println("線程"+team.id+" 結束:"+team.type+" 結束時間"+(team.starttime+team.totaltime));}}}private static void readerthread(int n)//讀者優先{q1=new PriorityQueue<thread>(comstart);end=new PriorityQueue<thread>(comend);for(int i=0;i<n;i++){q1.add(thread[i]);end.add(thread[i]);}int timeend=-1;//讀結束的時間最晚int writendtime=0;//寫操作結束的時間,如果有寫的狀態,那么thread start=q1.peek();thread finish=end.peek();while(!q1.isEmpty()||!end.isEmpty()){if(!q1.isEmpty()) {start=q1.peek();}if(!end.isEmpty()) {finish=end.peek();}if(start.starttime<=(finish.starttime+finish.totaltime)&&!q1.isEmpty())//可以開始讀寫操作{thread team=q1.poll();if(writendtime>start.starttime)//此時有寫的情況,需要等待阻塞,也就是將此隊列頭拋出修改開始時間然后再次入隊{team.starttime=writendtime;q1.add(team);end.remove(team);end.add(team);}else {//此時無寫的操作,無操作或者讀操作//System.out.println("線程"+team.id+" 開始:"+team.type+"操作 時間:"+team.starttime+" 結束時間"+(team.starttime+team.totaltime));if(team.type.equals("w"))//寫的情況,寫需要檢查是否阻塞自己如果有讀的情況則需要阻塞自己{int time2=timeend;if(time2<writendtime)time2=writendtime;if(team.starttime>=time2)//在這個時間前沒有任何讀或者寫的操作,上鎖,等于號一定有,因為都拋出它了,他的優先級一定最高{writendtime=team.starttime+team.totaltime;System.out.println("線程"+team.id+" 開始:"+team.type+"操作 時間:"+team.starttime+" 結束時間"+(team.starttime+team.totaltime));}else {//狀態還有讀操作,需要阻塞team.starttime=time2;q1.add(team);end.remove(team);end.add(team);}}else//讀的情況{System.out.println("線程"+team.id+" 開始:"+team.type+"操作 時間:"+team.starttime+" 結束時間"+(team.starttime+team.totaltime));if(team.starttime+team.totaltime>timeend){timeend=team.starttime+team.totaltime;}}}}else if(!end.isEmpty()){//某個結束操作在這個時間段thread team=end.poll();System.out.println("線程"+team.id+" 結束:"+team.type+" 結束時間"+(team.starttime+team.totaltime));}}}public static void main(String[] args) {System.out.println("請輸入n個線程程序"); int n=sc.nextInt();threadcreate(n);System.out.println("請輸入數字選擇讀者優先或者寫者優先\n1:讀者優先\n2:寫者優先");int index=sc.nextInt();while(index<1||index>2) {System.out.println("請輸入正確的數字");index=sc.nextInt();}if(index==1)//讀者優先{readerthread(n);}else {writerthread(n);}}static Comparator<thread>comstart=new Comparator<thread>() {//讀者優先的comparator接口,優先時間,時間相同則先返回public int compare(thread o1, thread o2) {// TODO 自動生成的方法存根if(o1.starttime==o2.starttime){return (int)(o1.type.charAt(0)-o2.type.charAt(0));// r w 先r后w}elsereturn o1.starttime-o2.starttime;//返回小根堆 }};static Comparator<thread>comstart2=new Comparator<thread>() {//寫者優先的public int compare(thread o1, thread o2) {// TODO 自動生成的方法存根if(o1.starttime==o2.starttime){return (int)(o2.type.charAt(0)-o1.type.charAt(0));// w r 先w后r}elsereturn o1.starttime-o2.starttime;//返回小根堆 }};static Comparator<thread>comend=new Comparator<thread>() {public int compare(thread o1, thread o2) {return (int)((o1.starttime+o1.totaltime)-(o2.starttime+o2.totaltime));}};static class thread{int id;String type;int starttime;int totaltime;public thread(int id,String type,int starttime,int totaltime){this.id=id;this.type=type;this.starttime=starttime;this.totaltime=totaltime;}}}測試用例:
讀者優先:
寫者優先:
本人水平有限,?,如果有大佬發現錯了,請指正。
如果對后端、爬蟲、數據結構算法等感性趣歡迎關注我的個人公眾號交流:bigsai
總結
以上是生活随笔為你收集整理的操作系统之多线程编程—读者优先/写者优先详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 操作系统之银行家算法—详解流程及案例数据
- 下一篇: 操作系统之存储管理——FIFO算法和LR