0

考虑一个非常简单的哈希表,其结构如下:

(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,getremove。我编写了一些测试来使用pcalls. 当我第一次开发一个在一个“ thread”上运行的测试时,(即只使用一个函数来调用pcalls)并且它成功了,我必须假设问题不存在,而是remove函数不是线程安全的。

删除实现如下:

(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,而不是编写纯函数式代码。

4

1 回答 1

0

似乎你不能在一个块内做def或做,因为它是一个全局的副作用,因此会扰乱你的交易。即使我不完全理解,除了根据文档不允许副作用之外,这就是搞砸一切的原因。defndosync

感谢 Freenode 上的人#clojure

于 2013-06-09T16:57:58.447 回答