В веб-приложении я пытаюсь сгенерировать уникальный безопасный для потоков идентификатор из ограниченного пула идентификаторов. Проблема, с которой я столкнулся, заключается в том, что между чтением и записью другой поток уже мог изменить структуру данных; вот почему я должен прибегнуть к сравнению и установке!
.
(def sid-batch 10)
(def sid-pool (atom {:cnt 0
:sids '()}))
(defn get-sid []
(let [{:keys [cnt sids] :as old} @sid-pool]
; use compare-and-set! here for atomic read & write
(if (empty? sids)
; generate more sids
(if (compare-and-set!
sid-pool
old
(-> old
(assoc :sids (range (inc cnt) (+ sid-batch cnt)))
(assoc :cnt (+ cnt sid-batch))))
; return newest sid or recur till "transaction" succeeds
cnt
(recur))
; get first sid
(if (compare-and-set! sid-pool old (update-in old [:sids] next))
; return first free sid or recur till "transaction" succeeds
(first sids)
(recur)))))
Существует ли более простой способ синхронизации операций чтения и записи без выполнения STM «вручную» и без использования поля в sid-pool
в качестве возвращаемого значения из swap!
?