2015-02-11 46 views
2

在SQL中,複製事務死鎖是相對容易的。是否有可能在Clojure中複製事務死鎖?

==SESSION1== 
begin tran 
update table1 set ... where ... 
[hold off further action - begin on next session] 

==SESSION2== 
begin 
update table1 set ... where ... 
[hold off further action - begin on next session] 

==SESSION3== 
<list blocked transactions - see session2> 
使用Clojure交易

現在 - 你不能只是打開他們,讓他們打開時,s表達式不要讓你做到這一點。

所以我很好奇上面的情況。

我的問題是:是否有可能在Clojure中複製事務死鎖?

+0

死鎖不會發生。活鎖可以。在任何情況下,你必須產生兩個線程並使用同步機制來實施一個場景。 – cgrand 2015-02-11 17:45:23

回答

0

Clojure中的STM旨在提供參考原子,一致性和隔離操作,而不鎖定。爲實現此目的,需要實現若干功能,如refs documentation中所述,但其中一個要點是要有一個「樂觀」策略,該策略處理每個事務的數據版本,並在寫入時比較該版本和參考版本。

這種樂觀策略也可以在數據庫中實現,例如,在Oracle

總之,Clojure中,如果你真的想創建一個僵局,你將不得不使用低級別mecanism,比如locking宏,明確創建一個對象(相同的Java​​)上的鎖,並明確管理對共享資源的訪問。

編輯:活鎖 此示例來自Clojure的編程,@cgrand和人的實施例。

(let [retry-count (agent 0) 
     x (ref 0)] 
    (try 
    (dosync ;; transaction A 
     @(future (dosync ;; transaction B 
       (send-off retry-count inc) 
       (ref-set x 1))) 
     (ref-set x 2)) 
    (catch Exception e (println (str "caught exception: " (.getMessage e)))) 
    (finally 
    (await retry-count))) 
    [@x @retry-count]) 

caught exception: Transaction failed after reaching retry limit 
[1 10000] 
user> 

事務A在repl線程中執行。事務B將在單獨的線程中執行,但由於future在A中被拒絕,它會阻塞,直到B完成。當A嘗試(ref-set x 2)時,x已經被B修改過,並且這觸發A的重試,這產生了新的線程和B事務...直到達到最大重試次數並引發異常。

+0

這很有趣。我可以在我的第一個Clojure事務(將來運行)中間做一個(Thread/sleep 1000)並阻止第二次Clojure事務嗎? (也就是說鎖宏實際上並不是必需的?) – hawkeye 2015-02-12 06:42:51

+1

實際上,第二個事務不會真的被阻塞,但它會重試,直到第一個事務完成或重試的限制達到(某些硬編碼常量:10000)。我將用一個例子編輯我的答案。 – 2015-02-12 16:48:20

+0

@ T.Gounelle在什麼時候事務A會意識到'x'的值被另一個事務改變了?我的意思是在需要時事務A得到x的'ref'? – lapots 2017-03-05 13:11:42

0

根據豐富的希基:

Clojure的STM和代理機制是無死鎖。它們不是阻止選擇性接收的消息傳遞系統。 STM在內部使用鎖定,但會自動執行鎖定衝突檢測和解決。

更多詳細資料請參閱this羣。