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是值,因此可以将它们分配给临时绑定。