考虑一个非常简单的哈希表,其结构如下:
(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
。我编写了一些测试来使用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,而不是编写纯函数式代码。