在Clojure中同步多个读者/单个编写器的线程

时间:2011-01-22 14:45:25

标签: multithreading concurrency clojure

我有一些非线程安全的代码(共享数据的编写器),只能以序列化的方式从多个线程调用,但我不想阻止任何其他线程安全的工作(多个读者)当没有调用此代码时。

这实际上是一个多读者/单一作家类型的锁定情况,作家需要排除读者和其他作者。

即。我有两个功能:

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

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

正在运行(可能在一个循环中)的一些线程如下:

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

如果任何单个线程正在执行writer函数,则所有其他线程都必须阻塞。即在任何时候:

  • 一个线程正在执行 作家和所有人 其他人被阻止
  • 多线程 执行读者功能,可能是一些线程 阻止等待执行 一旦所有读者完成,作者

在Clojure中实现这种同步的最佳方法是什么?

2 个答案:

答案 0 :(得分:3)

将您的数据放入ref。数据应该是Clojure数据结构(不是Java类)。使用dosync创建围绕读写的事务。

实施例。因为您将编写器拆分为单独的函数,所以该函数必须使用alter之类的函数修改ref。这样做需要一个事务(dosync)。你可以依赖于只在dosync中调用writer,但是你也可以在write中放入一个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来阅读共享引用。这不会阻止并发写入器。

答案 1 :(得分:0)

看看java.util.concurrent.locks.ReentrantReadWriteLock。这个类允许你有多个读者一次不在一个作家上相互竞争。