2011-01-22 64 views
3

我有一些非線程安全的代碼(一個共享數據的編寫器),它只能以串行方式從多個線程中調用,但我不想阻止任何其他線程安全的工作(多個讀者),當這個代碼沒有被調用。爲Clojure中的多個閱讀器/單個寫入器同步線程

這本質上是一個多讀者/單寫作者類型鎖定的情況,作家需要排除讀者和其他作者。

即我有兩個功能:

(defn reader-function [] ....) // only reads from shared data 

(defn writer-function [] ....) // writes to shared data 

並與多個正在運行的(可能在一個循環中)的線程執行以下操作:

(do 
    (reader-function) 
    ... 
    (writer-function)) 

如果任何單個線程正在執行的寫入器功能,所有其他線程必須阻止。即在任何一個時刻或者:

  • 一個線程正在執行 作家和所有 他人被阻塞
  • 多個線程 執行讀取功能,可能的一些線程是 阻塞等待執行 作家一旦所有讀者完成

在Clojure中實現這種同步的最佳方式是什麼?

回答

0

查看java.util.concurrent.locks.ReentrantReadWriteLock。這個類允許你有多個閱讀器一次不會在一個作家中相互競爭。

+0

RRWL將做到這一點,但你不應該使用它們來解決Clojure中的這個問題。如果您使用RRWL來保護您的數據,那麼您沒有充分利用Clojure的不可變數據結構,引用或STM。 Clojure的Clojure數據結構參考已經允許多個讀者。因爲它們是不可改變和持久的,所以它們可以在沒有阻止作者的情況下隨時解除。閱讀http://clojure.org/refs。 – 2011-01-22 15:41:42

+0

謝謝拉爾夫!看起來像是我所需要的。任何想法,如果有一個Clojure等價物或我需要使用Java互操作來獲得此功能? – mikera 2011-01-23 17:28:33

3

將您的數據存入ref。數據應該是Clojure數據結構(不是Java類)。使用dosync來創建讀寫周圍的事務。

例子。由於您將作者分成單獨的函數,因此該函數必須修改參考文件alter。這樣做需要交易(dosync)。您可以依賴於只在dosync中調用的作者,但是您也可以在寫入內部放置一個dosync,並依賴嵌套事務處理您想做的事情 - 這使編寫器可以安全地調用事務內外的事務。

(defn reader [shared] 
    (println "I see" @shared)) 

(defn writer [shared item] 
    (dosync 
    (println "Writing to shared") 
    (alter shared conj item))) 

;; combine the read and the write in a transaction 
(defn combine [shared item] 
    (dosync 
    (reader shared) 
    (writer shared item))) 

;; run a loop that adds n thread-specific items to the ref 
(defn test-loop [shared n] 
    (doseq [i (range n)] 
    (combine shared (str (System/identityHashCode (Thread/currentThread)) "-" i)) 
    (Thread/sleep 50))) 

;; run t threads adding n items in parallel 
(defn test-threaded [t n] 
    (let [shared (ref [])] 
    (doseq [_ (range t)] 
     (future (test-loop shared n))))) 

用類似(test-threaded 3 10)的東西運行測試。

此處瞭解詳情:http://clojure.org/refs

你沒有問這個情況,但需要注意的是任何人都可以在任何時間derefing它讀取共享裁判是很重要的。這不會阻止併發作者。

相關問題