oo的第二單元是講多執行緒的協作與控制,三次作業分別為fafs電梯,als電梯和三部需要協作的電梯。三次作業由淺入深,讓我們逐漸理解多執行緒的工作原理和執行狀況。
第一次作業:
第一次作業是傻瓜電梯,也就是完全不需要考慮捎帶策略,只需要簡單的把每乙個人都送到目的樓層就可以。與以往寫過的程式不同的是,這次要採取多執行緒的 模式,輸入和輸出並不同時,輸入是按照時間投放的,輸出也要包含時間資訊。這次作業主要是想教會我們生產者——消費者模型的使用。然而,在第一次寫這次作業的時候,我把輸入當成生產者,排程器當作托盤,卻把每一條請求都當作了乙個消費者,試圖讓每一條指令單獨去跑(這或許就是我對多執行緒最初的理解,然而其實這次作業中的多執行緒是讓我們將輸出和輸入兩個執行緒併發執行),導致出現了很離譜的錯誤。並且,在試圖保證每兩條請求的執行不能夠出現重疊,我還想在排程器中設定該條指令是否結束的標誌位,這個方法看上去是可行的,但是我當時對於notifyall,wait等還不是很理解,甚至想嘗試在run()方法的最後加入notifyall(),企圖來喚醒正在等待的執行緒,發現根本無動於衷23333,最後我甚至想到了wait(100)再去查詢的zz方法,雖然這樣能夠跑出來,但是這是乙個浪費cpu的輪詢,而且執行緒會頻繁的被喚醒然後wait。最終,在我積極的與同學交流的過程中,終於慢慢理解了這道題的本意,將其改成了輸入生產者,輸出消費者,變成了比較正常的思路。但改完之後,我還是遇到了問題,那就是怎麼樣讓他停下來。輸入執行緒根據給的樣例遇到null就會停,那輸出怎麼辦。於是,我在輸入執行緒遇到null停止之前把null也傳進來,輸出執行緒遇到null也停止,這樣終於搞定了第一次作業。
類圖如下:
度量分析如下:
可以看出,這次由於正確的採用了生產者消費者模式,所以各個類和方法的複雜度都比較低,設計的比較好。
第二次作業:
第二次作業是als電梯,也就是要採取捎帶策略的電梯。指導書中給的捎帶方法為將與主請求同一方向的請求作為捎帶請求加入,並且不斷地去更新主請求。我採用的方法是將第一條請求作為主請求,然後將與他同方向的,並且是當前執行到的樓層可以攜帶的請求全部加到電梯執行的請求佇列中,然後將電梯請求佇列中的請求都跑完並且電梯中沒有人作為一次主請求及其捎帶請求跑完的判斷條件。我覺得不斷公升級主請求和我採用的方法實現起來的結構是基本一樣的。由於在電梯開關門以及每到一層都可能會輸入能夠捎帶的請求,所以在每一次電梯開關門上下層,我都會判斷一次是否有能夠捎帶進來的請求。這種方法會有不停的對請求佇列遍歷去查詢的問題,不過貌似對40條指令的遍歷並不會太佔cpu。然而,大閘蟹還是在強測中因為乙個小小小小小小小的問題,被炸掉了一大半0.0。在判斷捎帶的時候,我採用的是判斷讀到的請求的進入樓層》=當前樓層並且方向向上,以及進入樓層<=當前樓層並且方向向下這樣的條件來判斷的,為了節省字元數,滿足checkstyle,我將這些if分開巢狀,然後就出現了在剛剛上去到達的樓層開始有一堆請求要向下,但是這些請求進的都是》=的那個if,導致並沒有帶著他們走下去0.0。
對於優化,我想了這幾種策略。一是在去接主請求的路上可以把能夠在主請求樓層之前出去的請求先送過去,以此來解決那些上來就16-1,後面卻跟著一些1-2,1-3之類的測試點。對於尋找主請求的時候,如果只是找第一條作為主請求,那麼15-1,16-1,17-1這樣的就會不停的上下,所以在尋找主請求的時候我也盡可能讓它一次性能夠覆蓋到足夠多的請求,來節省時間。(然而再怎麼優化,由於上面那個小小小小小小小的問題我還是涼了)。
類圖如下:
度量分析如下:
可以看出,架構基本和第一次一樣,但是由於我在每一次開關門以及每一層上下樓都去判斷是否有捎帶的請求,導致電梯執行緒的複雜度較高。
第三次作業:
第三次作業是三颱電梯一起執行,各自有各自的可達樓層,有各自的載客量,對於某些請求,還需要讓乘客換成(這難道不是乘客應該考慮的事情嗎2333,還有那詭異的殘次品c電梯以及只有c才能到達的神秘三樓)。我大致採用了之前的架構,在get方法中增加了對於電梯名字以及是否是該架電梯可以送的人的判斷。為了處理換乘問題,我新建了乙個類,其中包含兩個personrequest物件,用來拆分開需要換乘的請求。在執行一條請求時,判斷其中第二個personrequest物件是否為null,不是的話就將其壓到排程器的佇列裡面。
怎麼樣讓電梯停下來是我本次作業遇到的最難的問題。由於我之前都是往裡面壓null,讀到了才停,而這一次,如果依舊是讀到null停的話可能會在之後分來出來的請求無法執行,會被炸掉。於是我就想讓讀到null不停下也不拿走,而是更改標誌位空跑,知道分離過的請求全部跑完才去停。然後我就發現會有乙個請求一直在跑null= =。既然這樣,那我就讓null被拿走,然後輸入null的時候多輸入兩個,我以為這樣三個電梯都會讀到null停下來,然而,有乙個電梯會把所有的null都搶走然後就沒有然後了= =。最終,我發現,為什麼要在輸入的時候搞進去null呢,我為什麼不再所有要分離的指令都搞定的時候再插入null讓電梯停下來...菜到流淚(⊙﹏⊙)
然而,最讓我想不到的是,又有乙個小小小小小小小的bug炸掉了我強測一大半的點。我在有乙個電梯中用來計人數的計數器忘記了清零= =。而且所有炸我的還全部是隨機生成的資料,甚至被同學hach14次也全部都是隨即資料亂炸0.0。de掉這個bug甚至用了一天。真是寫程式不細心,debug兩行淚 ┭┮﹏┭┮
類圖如下:
度量分析如下:
可以看出,架構其實還是差不多的,只是原來是用personrequest現在變成了我自己新建的類,並且輸出採用了加鎖的靜態方法。
由於和第二次架構基本一樣,複雜度高的地方也基本一樣。
bug分析:
這三次作業,我自己的bug大都是不細心導致的。(然而都是小bug卻導致了大問題,非洲人無話可說0.0)
對與尋找別人的bug,第一次作業,大家都不怎麼會測並且傻瓜電梯實在是難出bug,隨意根本沒有hack到別人。第二次作業,我大部分採用的是我自己遇到的bug,比如停不下來,比如某些捎帶請求拿了進去卻沒辦法跑,成功發現了一台能夠上天堂的電梯和一台吃人的電梯。第三次作業,我認為大家跑應該是沒有問題的,大部分的問題是某些情況停不下來(然而我自己卻是跑丟了0.0,或許我找的方向不怎麼對),於是我採用了隨機資料去測試其他人看能否停下來,停不下來才交,結果只發現了很少的錯誤,而同組的barsaker是直接交隨機資料,結果卻炸掉了好多好多人,(雖然全部是同質)。
體會與感想:
這一單元給我的感想是,寫的時候開開心心,出分的時候想沙河主樓躍解千愁。但不管怎麼樣,對於多執行緒還是逐漸理解了的。多執行緒的這種不確定性,bug的不可復現性也大大大大大大鍛鍊了我們的debug能力。這一單元的測評還是比較嚴格的,雖然像我這種的非到小bug炸全家的不多見,並且好像也找不出什麼能夠拯救我這種每次都是因為一點點點點小bug被大面積炸的可憐孩子(非洲人無話可說)。
總而言之,這一單元是有挑戰的一單元,也是極大鍛鍊我們能力的一單元。
OO第二單元總結
本單元的作業總體來說比較愉快,畢竟不像上次一樣次次重構。本單元為電梯系列問題,涉及到多執行緒問題。簡單起見,我使用的是生產者 消費者模式。本次作業要求實現單部可稍帶電梯。看完題目後我認為生產者 消費者模式非常適合解決這個問題。本次電梯我採用的是look方法。本方法核心即在於電梯方向的判斷,這在dis...
OO第二單元總結
共享資料類 在總結後面的3.基於度量的程式結構分析部分,本人根據展示的uml類圖更加詳細的講解了具體的協同結構工作原理。通過對實現以上操作的共享資料類中的方法設定synchronized,從而實現執行緒對共享資料的訪問同步。ocplsp ispdip 根據以上類圖,分析本次作業設計思路如下 2 根據...
OO第二單元總結
第二單元總結 第一次作業 思路與反思 uml類圖 度量分析 耦合度 第二次作業 思路 第二次作業與第一次的迭代在於電梯增加 人數限制 樓層改變,我依舊用的look演算法,在第一次作業的基礎上修改細節即可,多部電梯要求實現執行緒安全,由於我使用的look演算法,電梯盲目執行,沒有更高階的排程,只需要在...