2011-01-22 8 views
3

スレッドセーフではないコード(ライターから共有データへ)はシリアル化された方法で複数のスレッドからしか呼び出せませんが、ブロックしたくありませんこのコードが呼び出されていないときは、他のスレッドセーフな作業(複数のリーダー)。Clojureで複数のリーダー/シングルライターのスレッドを同期する

これは基本的に、複数のリーダー/単一のライタータイプのロック状況であり、ライターはリーダーと他のライターの両方を除外する必要があります。

私は2つの機能があります。すなわち:任意の単一のスレッドがライタ機能を実行している場合

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

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

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

そして(おそらくループ内で)実行しているスレッドの数は、次のように他のすべてのスレッドはブロックする必要があります。つまりは、いずれかの時点で、次のいずれか

  • つのスレッドが ライターを実行しており、すべての 他は
  • 複数のスレッドが がリーダー機能を実行しているブロックされている、おそらくいくつかのスレッドが が ライターを実行するために待機してブロックされています一度すべての読者が完了したら

Clojureでこの種の同期を達成する最良の方法は何ですか?

答えて

0

java.util.concurrent.locks.ReentrantReadWriteLockを見てください。このクラスを使用すると、一度に1つのライターで互いに競合しない複数のリーダーを持つことができます。

+0

RRWLはこれを行いますが、Clojureでこの問題を解決するために使用しないでください。 RRWLを使用してデータを保護する場合、Clojureの不変なデータ構造、参照、またはSTMを利用していません。 ClojureのClojureデータ構造の参考文献は、すでに複数の読者を許しています。彼らは不変で永続的なので、いつでもライターをブロックすることなくderef'edすることができます。 http://clojure.org/refsを読んでください。 –

+0

ありがとうラルフ!それは私が必要とする行に沿っているように見えます。 Clojureに相当するものがあるかどうか、またはこの機能を実現するためにJava相互運用機能を使用する必要があるかどうかについての考えはありますか? – mikera

+0

@mikera:Alex Millerがコメントで述べたように、refsはこのように動作しますが、私が知る限り、Clojureにはこれを行うための特定の機能がありません。 – Ralph

3

refにデータを入力してください。データはClojureデータ構造でなければなりません(Javaクラスではありません)。 dosyncを使用して、読み取りと書き込みを中心にトランザクションを作成します。

例。あなたの作家を別の関数に分割するので、その関数はalterのようなものでrefを修正する必要があります。そうするには取引(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で共有REFを読むことができることに注意することが重要です。これは並行ライターをブロックしません。

+0

@mikera、この書き込みは外部プロセスの副作用ですか?その場合、私はここでrefsがここで仕事をすることはできないと考えています。これは、同じプロセス共有状態でのみ使用されます。私は、エージェントを使った部分解を使うことしか知りません。 – bmillare

+0

こんにちはアレックス、答えをありがとう! 100%Clojureのアプローチとしては素晴らしいですが、問題は、作者が直接制御できない副作用コード(実際にはJavaライブラリ内)を実行していることです。したがって、Clojureトランザクションでうまく動作せず、私は何とかライブラリのロック要件を反映する必要があります.... – mikera

関連する問題