動機
感覺自己不曾了解過Concurrent programming,所以來看這本 看能不能得到一些直覺
共享變量的一致性
- 原子性: 在操作時變數的狀態不會被其他人改變
- 有序性: 指令產生的效果要照順序發生 (指令重排)
- 可見性: 別人改了其他地方看的到嗎? (快取問題)
要看Java Memory Model,會有更好的解釋 同時Java Memory Model也提出一些原則讓我們預期做Concurrent時會發生什麼事 並不限定在Java上他提出的原則是通用的
隔離變數
隔離變數的手法
- lock, access in order => 所有變數都在同一個地方
- message passing(actor, CSP), copy data(copy-on-write) => 變數在不一樣的地方
避免deadlock
- timeout then release => live lock(deadlock doesn’t last forever, no progress is made either)
- allow interrupt
- check states before do something => CAS(non-lock,atomic var), cond var
avoiding alien method calls while holding a lock are applicable to any language with threads and locks
如何形成deadlock
def procA():
lockA.lock()
...
lockB.lock()
...
def procB():
lockB.lock()
...
lockA.lock()
...
只要在一個瞬間能
- 拿到對方想要的資源 (用圖來看就是對方的箭頭指向自己)
- 對方拿到自己想要的資源 (自己的箭頭指向對方)
- 沒有人願意放開手上的資源
- 這些資源都是唯一的只能一個proc持有 (圖的node只能有一個,我打前面三點的時候忘了這個)
Priority inversion(打的時候想起來有讀過,但書上沒有)
高優先序的proc因為其他proc在critical zone而被block, 所以在context switch時讓其他優先序低的proc先執行了
這裡要想到的是critical zone會讓所有用到的proc被綁在一起
在context switch時所有用到critical zone的proc會被綁在一起 因為都要等critical zone
所以可以看成在context switch時可以把proc分成 有/無critical zone
那無critical zone的優先序就是原本的優先序 但有critical zone的優先序是正位於critical zone的proc的優先序
avoid lock
第二章中的第三天提到數字數的程式
原本是只有一個counter從queue拿parser生出的task
第二版把counter生出很多個counter想說可以提升效率 但因為counter們反覆access紀錄結果的map所以基本上沒辦法讓多個counter同時執行
所以把map改成可以Concurrent的map,效率順利上升了
第三版不在把所有counter的紀錄留在同一份map上 而是之後再一次加總完,效率又上去了
就算是可Concurrent的map,但還是會有contention 還是會等(non-lock)
STM與atomic var與actor的比較
In addition to atoms, Clojure also provides agents and refs: • Atoms enable independent, synchronous changes to single values. (atomic var) • Agents enable independent, asynchronous changes to single values. (可以當成actor) • Refs enable coordinated, synchronous changes to multiple values. (STM)
CSP
其實就是pipe,但如何synchronize? 在讀或寫的時候,不能被打斷 並block在讀不到資料時(除非pipe有buffer可以存資料,這樣寫就不會block)
actor與channel可以當成把queue從actor抽出來 獨立讓任何process都能存取