Как синхронизировать чтение и запись в Clojure?

В веб-приложении я пытаюсь сгенерировать уникальный безопасный для потоков идентификатор из ограниченного пула идентификаторов. Проблема, с которой я столкнулся, заключается в том, что между чтением и записью другой поток уже мог изменить структуру данных; вот почему я должен прибегнуть к сравнению и установке! .

(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! ?

6
задан Philip Kamenarsky 30 March 2012 в 09:39
поделиться