2011-06-19 5 views
7

私はキューにファイルへの書き込みを含む先物処理ジョブのグループを持っています。 1人の未来だけが特定のファイルに一度にアクセスするようにするための慣用的な方法は何ですか?clojureで慣用的なファイルロック?

答えて

8

これを保証するには、ロックの代わりにエージェントを使用しますか?

私は、ロックやロックを使用するよりも、メモリやディスクにあるかどうかに関係なく、安全なガード共有可変状態にすることを考えています。

一度に1つのエージェントを作成し、そのエージェントにアクセス試行を送信すると、特定のファイルにアクセスするときにスレッド上でのみ確実にアクセスできるようになります。

(use 'clojure.contrib.duck-streams) 

(defn file-agent [file-name] 
    (add-watch (agent nil) :file-writer 
    (fn [key agent old new] 
     (append-spit file-name new)))) 

(defn async-append [file-agent content] 
    (send file-agent (constantly content))) 

、エージェントを通して、あなたのファイルを追加します:

(async-append "content written to file" (file-agent "temp-file-name")) 

あなたはファイルの同期の使用が必要な場合、それはのawaitを達成することができた。このような例

。このように:

(defn sync-append [file-agent content] 
    (await (send file-agent (constantly content)))) 
+0

ニート!これについて私の頭を浮かべるには少し時間がかかりました。私は開いているファイルごとにエントリが含まれているマップへの参照を使用して終了しました。あなたのソリューションははるかに良いかもしれないように見えます。 – jhickner

+0

私はまだ何かが不明です - もし2つのスレッドが両方ともasync-appendを呼び出して同じファイル名を渡した場合、ファイルを開くのを止めないでください。 async-append内のfile-agentを呼び出すと、スレッドごとに一意のエージェントが作成されるようですね。 – jhickner

+0

不明な指示がありましたら申し訳ございませんが、ファイルごとに1つのファイルエージェントを作成し、非同期または同期追加が必要な場合は、async-appendまたはsync-appendのいずれかを使用して追加します。正しいエージェントを見つけるためにエージェントを地図の中に置いておくことができます。 –

1

私はClojureにこれ用の組み込み関数があるとは思っていませんが、標準のJava IO関数を使ってこれを行うことができます。これは次のようになります。

(import '(java.io File RandomAccessFile)) 

(def f (File. "/tmp/lock.file")) 
(def channel (.getChannel (RandomAccessFile. f "rw"))) 
(def lock (.lock channel)) 
(.release lock) 
(.close channel) 
+0

最初にこの方法を試しましたが、残念ながらこの方法はファイルを他のプロセスからのアクセスからロックするためにのみ有効です。同じVM内の複数のスレッドを操作する場合、ファイルが使用可能になるまでブロックしないで、同じVM内の別のスレッドがすでにファイルをロックしていると、lockとtryLockは両方とも例外をスローします。 – jhickner

4

私は次のように使用されているコアClojureの機能lockingを使用します。ここでは

(locking some-object 
    (do-whatever-you-like)) 

some-objectは、ファイル自体も、あるいはあなたが同期したい任意のオブジェクト可能性がどちらか(複数のファイルを1つのロックで保護したい場合には意味があります)。

標準ではJVMのオブジェクトロックが使用されているため、基本的にはJavaのコードブロックと同期しています。

関連する問題