日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

第二单元作业——电梯模拟总结

發布時間:2024/4/15 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第二单元作业——电梯模拟总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、設計策略

  1. 單部先來先服務電梯

  第一次作業采用了最基本的生產者-消費者模型,電梯請求是模型中的商品,將控制器作為存儲請求的倉庫,主線程作為生產者向倉庫存放請求,電梯作為消費者從倉庫取出請求并處理。先來先服務的調度策略中,電梯一次只會處理一個請求,因此可將請求作為一個操作的原子。控制器儲存請求使用隊列結構,電梯每次取出隊列首位的請求執行。

?

  2. 單部可捎帶電梯

  第二次作業沿用第一次作業的結構,區別在于為了實現可捎帶,電梯需要同時處理多條請求,因此不能再以一整個請求作為操作原子,而需要破拆成更小的任務。

  我設立的電梯的原子操作分為乘客進入、乘客退出、上移一層和下移一層,電梯在取出一條請求時將請求拆分成一個原子操作的序列,之后順序執行隊列中的操作,即可完成請求。捎帶任務時,由于捎帶的條件是請求與電梯運行方向相同且乘客上下的樓層都在電梯的運行方向上,被捎帶的請求的原子操作序列可以和電梯當前的操作序列融合,實現多個任務共同執行。

  優化方面嘗試實現look算法。當主進程試圖將一個新請求放入控制器時,首先判斷該請求能否立即被捎帶,若可以,則直接加入電梯的操作隊列中,否則放入控制器的存儲鏈表中。控制器的存儲鏈表分為兩條,一條儲存上行任務,一條儲存下行鏈表,同時記錄上行鏈表中起始樓層最低和下行鏈表中起始樓層最高的請求。當電梯執行完當前的操作序列,準備從控制器中取出一個新任務時,電梯將從這兩個最遠端的任務中選取起始樓層較近的一個執行。這個算法的目的是使電梯在一次上下行中能夠盡量多的進行捎帶,選取最遠端的請求能夠將同方向上所有的任務全部捎帶。

?

  3. 三部停靠樓層不同的,有負載上限的電梯

  第三次作業與第二次作業的區別在于:1)多部電梯。需要考慮如何給三個電梯分配任務。2)電梯停靠樓層不同。一個請求可能不能由一部電梯單獨完成,不能以請求為單位向電梯分配任務,需要進行拆分。3)有負載上限。電梯可能不能將所有可捎帶的請求全部捎帶,需要進行選擇。

  為了沿用第二次作業中的結構,我在第三次作業中設計了一個主控制器和每個電梯各自的控制器。主控制器負責對請求進行預處理和將處理后的請求分配給每個電梯的控制器,請求的預處理即為此請求規劃路線,包括是否換乘、在哪層換乘、乘坐哪部電梯。為簡化問題,我通過靜態方法規劃路徑,與電梯當前所在的樓層與狀態無關,可直達的請求必選擇直達的方式,不得不轉乘的任務選擇固定的樓層進行換乘。主線程經過主控制器的判斷后,將處理的請求分配給對應的電梯的控制器,每個電梯處理各自的控制器中的任務的方式和第二次作業相近。區別在于電梯間對于換乘的通信和超過負載的處理方式。

  在電梯間的協調運作上,我讓電梯在當前沒有能夠執行的請求時,向未來將出現請求,即來自其他電梯的換乘請求的樓層移動,但當移動過程中出現可立即執行的請求時,移動需要被打斷,去響應需要立即執行的請求。為實現這一功能,需要將未來將換乘本電梯的任務存儲在本電梯控制器的另一個隊列中,當電梯完成一個請求(執行乘客退出的原子操作)時,檢查該乘客是否需要換乘,若需要,則將下一步需要乘坐的電梯的控制器中該乘客對應的存儲于未來任務序列中的任務移動到可立即執行的任務序列中。而當一個電梯沒有可立即執行的任務時,向未來任務隊列中首項的任務的換乘樓層移動。

  對于超過負載的情況,我使用拒載的方式。當電梯執行到某一條乘客進入的指令時,若電梯負載已滿,則不讓乘客進入,同時清除操作序列中該乘客退出的指令,然后將該乘客對應的請求重新加回到控制器的可立即執行隊列中。

  優化方面,在任務分配上,由于使用了靜態分配的方式,性能上已經受到限制,只能通過調整優先級調整各個電梯的工作量,從概率上能夠提升一點效率。

?

二、 度量分析

  1. 單部先來先服務電梯

  電梯類的run函數里由于包含了處理一個請求的流程(移動、開關門、乘客上下),有面向過程的成分在,因此方法較長,復雜度較高。這個問題在三次作業中都有體現。

  時序圖是一個基本的生產者消費者模型。

?

  2.?單部可捎帶電梯

  復雜度較高的幾個方法中,控制器的putRequest是主線程向控制器存放請求的函數,里面包含了維護look算法的上行下行請求鏈表的步驟。getRequest是電梯向控制器索取主任務的方法,同時包含了確定主任務后檢索所有可捎帶任務的步驟。電梯的pickQuest是將一個請求分解成原子操作序列的方法。Run是電梯每次從原子序列中取出一條指令并執行的方法。這些方法控制分枝較多,代碼較長,同時覆蓋了多個功能,不太符合面對對象的思想,我沒有將這些函數進行拆分的主要原因是我不知道該給新的函數起什么名字。。。

  時序圖比起上一次作業多出了一條由倉庫主動(主線程運行)將任務塞給電梯的路線

?

  3.?三部停靠樓層不同的,有負載上限的電梯

  第三次作業的復雜度由于大部分沿用第二次作業的結構,沒有太大的變化,多出一個復雜度較高函數是EditedRequest的構造函數,根據乘客的起止樓層規劃線路,控制分枝很多。

  在第三次作業中存在主線程修改電梯對象、電梯線程修改自身、電梯線程修改另一個電梯對象的過程,線程之間的互斥關系比較復雜,最終交上的作業中也依然存在著一些時序上混亂的問題,沒能取得理想的成績。

  從soild原則上分析,由于這一次沒有使用類的繼承,主要從單一功能原則和開放封閉原則分析。在這一次的控制器設計上,我按照管理范圍將控制器分為了三個層次:管理所有電梯,向各電梯分配任務的主控制器、存儲主控制器分配的任務,決定執行策略的字控制器和將任務轉換成原子操作,然后執行的電梯本身,從描述上就可以看出,每個層級依然承擔著多項任務,這也導致我的程序中出現長度大,判斷復雜的方法,在單一責任的角度看,程序的分層還不夠抽象,導致部分功能混雜在一起。

  我第三次作業中的每一部電梯和它的子控制器之間的交互移植自第二次作業。但為了實現讓電梯拒載,讓子控制器存儲將來換乘的任務,讓電梯在完成一個任務時同時其他電梯它完成了該任務等功能,還需要對第二次作業進行一些修改,其中大部分的改動是通過新增成員變量和方法實現的,但一些方法中邏輯上的控制和判斷依然需要修改,那些復雜度高的長函數是尤其的重災區。這違反開放封閉原則,我也切身的體會到了修改完這些方法之后debug是多么痛苦,這也側面的證明了單一責任原則有多么重要。

?

三、bug分析

  在這三次作業中我所遇到的bug主要是線程安全問題的的bug。由于濫用synchronized導致的死鎖和由于synchronized了錯誤的對象導致的線程不安全。

  我發現java中一個線程可以通過synchronized嵌套來占據多個對象的鎖,但wait只能釋放其中一個鎖,而不能將全部的鎖釋放。在我的電梯中,由于主線程(producer)可能調用控制器(tray)中的putRequest函數時可能直接將請求(product)交給電梯(customer),電梯線程在調用控制器的getRequest時需要先掌握自身的鎖,getRequest函數需要得到控制器的鎖,若控制器中沒有指令,電梯線程就會放開控制器的鎖進入阻塞,但電梯線程沒有釋放電梯自身的鎖,因此當主線程向將一個請求直接交給電梯時,就會發生死鎖。

  對于這種情況我沒有好的解決辦法,只能盡量調整同步塊的范圍,使其盡量不發生嵌套,但這又導致了另一種問題。我的控制器中有這樣的一類表達:if (elev.canPickUp(request)) {elev.pickRequest();}。其中elev的兩個函數是電梯類中的兩個同步函數。可見兩個函數邏輯上是應該緊接著連續執行的,但中間稍微將elev的鎖放開了一下,就導致可能有其他線程搶到鎖,插在中間執行,修改了elev的成員變量,導致電梯捎帶任務時出現錯誤。

  我認為會發生這樣的矛盾的根本原因是我沒有處理好方法的調用關系。我剛開始設計程序結構時是因為擔心cpu時間過高而放棄了讓電梯輪詢檢查控制器中有沒有新增的函數,但后續了解到,控制合理的輪詢不會增加太多的cpu時間,若我將主線程嚴格限制在只能訪問到控制器,由電梯輪詢檢查控制器是否改變,若改變則調整任務序列,也就不會出現上述的同步塊嵌套等問題。

?

四、檢測bug的策略

  第一、二次作業由于涉及的情況相對比較簡單,可以人工構造不同情況的數據,如上下行的轉向,等待后的再啟動空轉時的捎帶等等在自己編程中總結出來的需要進行處理的情況。進一步的檢測我通過自己寫的一個隨機測試數據生成器和定時輸入器進行隨機測試,將多個人的測試結果放在一起對比可以發現一些不正常的行為,猜測其原因并針對這一點構造數據,可以發現一些性能上的問題。

  第三次作業由于簡單的輸出難以進行壓力測試,復雜的輸出有難以判斷正誤,只使用隨機數據進行檢測,用一個模擬程序判斷輸出的結果正確或出現哪種錯誤。通過調整隨機數據生成的策略可以適當轉移測試的重點。

  沒有想到能比較好的檢查線程安全的方法。。。

?

五、心得體會

  多線程編程是在問題模型具有明顯的并發性時選擇的編程方法,這次實驗的電梯就是一個典型的例子。進行多線程編程首先要線程的劃分,確定模型的結構,這次實驗中,我將每一部電梯作為一個進程,輸入作為一個進程,我也見到有的同學為每一名乘客都建立了一條線程。確立進程后需要考慮的是進程間的隔離與通信,隔離是為了保證線程安全,互不干擾,通信則是線程間協作的需要。在線程安全上,我總結出的教訓是,最好不要讓一個線程能夠直接修改另一個線程的對象,在生產者-消費者模型中,生產者線程和消費者線程是通過倉庫這一緩沖區作為通信的中介,線程對象的每一個動作都應該是主動的索取,而不是被動的接收。這樣的設計可以保證線程對象不會被其他線程修改,不用考慮自身對象的同步性。緩沖區的設計需要注意每一個同步函數應該只被一類線程訪問,put函數只能被生產者線程訪問,get函數只能被消費者線程訪問,這可以簡化設計線程安全時需要考慮的情況,防止復雜的情況發生。有時線程之間的通信可能經過多個緩沖區,可能發生死鎖,這時可以使用動態加鎖等方法,避免死鎖發生。

轉載于:https://www.cnblogs.com/jinyangxinji/p/oo_homework_sum2.html

總結

以上是生活随笔為你收集整理的第二单元作业——电梯模拟总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。