为Clojure中的多个阅读器/单个写入器同步线程
问题描述:
我有一些非线程安全的代码(一个共享数据的编写器),它只能以串行方式从多个线程中调用,但我不想阻止任何其他线程安全的工作(多个读者),当这个代码没有被调用。为Clojure中的多个阅读器/单个写入器同步线程
这本质上是一个多读者/单写作者类型锁定的情况,作家需要排除读者和其他作者。
即我有两个功能:
(defn reader-function [] ....) // only reads from shared data
(defn writer-function [] ....) // writes to shared data
并与多个正在运行的(可能在一个循环中)的线程执行以下操作:
(do
(reader-function)
...
(writer-function))
如果任何单个线程正在执行的写入器功能,所有其他线程必须阻止。即在任何一个时刻或者:
- 一个线程正在执行 作家和所有 他人被阻塞
- 多个线程 执行读取功能,可能的一些线程是 阻塞等待执行 作家一旦所有读者完成
在Clojure中实现这种同步的最佳方式是什么?
答
查看java.util.concurrent.locks.ReentrantReadWriteLock。这个类允许你有多个阅读器一次不会在一个作家中相互竞争。
答
将您的数据存入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它读取共享裁判是很重要的。这不会阻止并发作者。
RRWL将做到这一点,但你不应该使用它们来解决Clojure中的这个问题。如果您使用RRWL来保护您的数据,那么您没有充分利用Clojure的不可变数据结构,引用或STM。 Clojure的Clojure数据结构参考已经允许多个读者。因为它们是不可改变和持久的,所以它们可以在没有阻止作者的情况下随时解除。阅读http://clojure.org/refs。 – 2011-01-22 15:41:42
谢谢拉尔夫!看起来像是我所需要的。任何想法,如果有一个Clojure等价物或我需要使用Java互操作来获得此功能? – mikera 2011-01-23 17:28:33