Concurrency Clojure STM:不一致删除
考虑一个非常简单的哈希表,其结构如下:Concurrency Clojure STM:不一致删除,concurrency,clojure,transactions,stm,Concurrency,Clojure,Transactions,Stm,考虑一个非常简单的哈希表,其结构如下: (defn make-hashtable [cap] (let [tablesize (int (Math/ceil (* cap 1.30)))] {:tablesize tablesize :capacity cap :size (ref 0) :vector (vec (map (fn [_] (ref '())) (range tablesize))) :type :
(defn make-hashtable
[cap]
(let
[tablesize (int (Math/ceil (* cap 1.30)))]
{:tablesize tablesize
:capacity cap
:size (ref 0)
:vector (vec (map (fn [_] (ref '())) (range tablesize)))
:type :hashtable}))
我有它的基本操作,例如put
、get
和remove
。我编写了一些测试,使用pcall
并行测试它们。当我第一次开发了一个在一个“线程
”上运行的测试(即只使用一个函数调用pcall
)并且成功时,我必须假设问题不在那里,而是在删除
函数中,它不是线程安全的
删除操作的实现如下所示:
(defn mht-remove
[table key]
(let [pos (table-pos table key)]
(dosync
(let [bucket @((:vector table) pos)]
(ensure (:size table))
(ensure ((:vector table) pos))
(defn equalskey?
[x]
(= (:key x) key))
(when (some equalskey? bucket)
(ref-set ((:vector table) pos) (remove equalskey? bucket))
(alter (:size table) dec))))))
奇怪的是,一个只包含一个元素的桶甚至没有被移除。这很奇怪,因为只有向量的元素是refs,而不是整个向量。
问题:为什么这段代码不是线程安全的,我可能做错了什么?
注意:我知道很多人会试图对该应用程序的设计发表评论,但这不是我感兴趣的答案。我想了解clojure的STM,而不是编写纯粹的功能代码。似乎您无法在
dosync
块内执行def
或defn
,因为它是一种全局副作用,因此会干扰您的事务。尽管我不完全理解,除了根据文档不允许有副作用外,这是把一切搞砸的原因
感谢Freenode的
#clojure
上的家伙们,还有更多:不要在函数内部使用def
或defn
,句号。即使没有dosync
,它也会弄乱单线程代码。请使用“let”而不是“def”:clojure fns是值,因此可以将它们分配给临时绑定。