【发布时间】:2018-12-11 16:31:07
【问题描述】:
我在 clojure 中有一段代码应该独立运行。假设这个函数是
(defn isolate [string1])
很容易在所有输入上隔离整个函数,这样调用它:
(def o (Object. ))
(locking o (isolate string1))
但是这只允许一个进程/线程同时访问隔离。
我现在实现的是以下内容:
(def current-locks (ref {}))
(defn mergeReverse [x y] (merge y x))
(defn merge-with-current-locks [key val]
(dosync (alter current-locks mergeReverse {key val})))
(defn remove-lock [key]
(dosync (alter current-locks dissoc key)))
最后线程阻塞调用这个方法
(defn block-until-free [key val]
(let [_ (merge-with-current-locks key val)]
(if (dosync (and (contains? current-locks key)
(not= (get current-locks key) val)))
(do
(Thread/sleep 10)
(block-until-free key val)))))
正如您在解决方案中看到的那样,我在这里使用了键和值,虽然我只锁定键,但是能够使用映射而不是数组是有益的,因为我使用了仅当映射时才在映射中合并的合并属性不包含这个值,因为 current-locks 是 ref 我使用了 alter 并交换了合并输入以获得所需的行为。
据我所知(并且我对其进行了测试),这个 hack 是有效的。但我的问题是我怎样才能以正确的 clojure 方式做到这一点?这个解决方案看起来很复杂
当然,一旦 critical 函数被执行,remove-lock 就必须被调用。
【问题讨论】:
-
你能在这个例子中添加一个动机/用例吗?由于每个线程都有自己的局部变量副本,并且由于函数输入在 Clojure 中是不可变的,因此似乎每个线程都已完全隔离。如果您希望改变某些共享的全局状态,则不会在您的示例中显示。
-
对于数据库表中特定标签下的每个附加值,我需要调用服务并更新该值和该标签中的每个值。同时,没有其他进程应该尝试更新标签。这就是为什么我想在我的服务仍在进行计算时阻止所有其他进程访问这个关键功能
-
这通常不会同时发生,但当它发生时需要被阻止
标签: concurrency clojure