Leetcode concurrency #1116 Print Zero Even Odd (in golang)
之前寫了#1114和#1115,都是用channel互相通知,叫正確的人起來做事;這在golang中算是很常見的作法,但這次的題目我想用比較傳統的方式解決,我將題目轉成一種producer-consumer的架構來解。
照慣例,題目解析:有一個class內有三個method,分別是印出0、偶數和奇數,跑三個thread各run一個method,輸入一個n要與0依序印出。舉例來說:n = 5,印出來的結果是:0102030405,依此類推。
這次解決的方法有點偷懶,正常的producer-consumer架構是要用一個queue,把東西丟入然後由consumer取出運算,但我只用兩個整數表示這個隊列,就沒去處理enqueue和dequeue的邏輯。
相比前面的解答算是再長了一些,這次用到一個互斥鎖來同步狀態,當要存取狀態時要取得鎖才有辦法繼續。也有在判斷條件內加入中止條件,也就是狀態是-1時就結束迴圈。用到鎖就比較繁複,有時間的話會試試看有沒有辦法把解鎖的地方處理的更漂亮。
若是consumer要做的事都一樣,這樣的寫法就足夠了,起多個goroutine可以有效加速消化。但是這次的題目會有一個edge case:因為是三人搶一鎖,而且每個人各司其職,所以有可能會starvation。舉例來說:當狀態curr = 2,理當由even接手,但若不幸的是,even搶不到鎖,變成是zero和odd兩個人互相把鎖丟來丟去,就空轉了。所以解答改良版如下:
變得更長了!兩個重點:一個是使用RWLock而不是互斥鎖,這樣在讀取狀態時人人有機會,不會發生搶不到的情況;其二,讀取鎖放掉後,若要繼續做事需要拿寫入鎖,但在拿到寫入鎖後,還是必須再判斷一次狀態,因為鎖放掉後就有可能有人改變狀態(雖然這題不會發生這種事,因為各司其職)。