Пример компоновки программной транзакционной памяти

11

Одно из главных преимуществ программной транзакционной памяти, которое всегда упоминается, - это возможность компоновки и модульность. Различные фрагменты могут быть объединены для получения более крупных компонентов. В программах, основанных на блокировке, это часто не так.

Я ищу простой пример, иллюстрирующий это с помощью реального кода. Я бы предпочел пример в Clojure, но с Хаскеллом тоже все в порядке. Бонусные баллы, если в примере также показан некоторый код на основе блокировки, который не может быть легко составлен.

dbyrne
источник
1
Интересно, но для меня это звучит больше как вопрос StackOverflow.
Стив
Этот вопрос был задан там через 4 минуты. stackoverflow.com/questions/5518546/… Будет ли кто-нибудь перенести и объединить этот вопрос (если это возможно)?
Работа
Да, после того, как я разместил это здесь, я понял, что, вероятно, будет лучше на Stackoverflow. Если кто-то может слить это, это нормально для меня.
dbyrne

Ответы:

9

Предположим, у вас есть несколько банковских счетов:

(def accounts 
 [(ref 0) 
  (ref 10) 
  (ref 20) 
  (ref 30)])

И атомная «передаточная» функция:

(defn transfer [src-account dest-account amount]
  (dosync
    (alter dest-account + amount)
    (alter src-account - amount)))

Который работает следующим образом:

(transfer (accounts 1) (accounts 0) 5)

(map deref accounts)
=> (5 5 20 30)

Затем вы можете легко составить функцию переноса, чтобы создать транзакцию более высокого уровня, например, перенос с нескольких учетных записей:

(defn transfer-from-all [src-accounts dest-account amount]
  (dosync
    (doseq [src src-accounts] 
      (transfer src dest-account amount))))

(transfer-from-all 
  [(accounts 0) (accounts 1) (accounts 2)] 
  (accounts 3) 
  5)

(map deref accounts)
=> (0 0 15 45)

Обратите внимание, что все множественные переносы происходили в одной объединенной транзакции, то есть было возможно «составить» меньшие транзакции.

Сделать это с блокировками очень быстро будет сложно: если учетные записи необходимо заблокировать по отдельности, вам нужно будет сделать что-то вроде установления протокола по порядку получения блокировки, чтобы избежать взаимных блокировок. Сделать ошибку, которую трудно обнаружить, очень легко. СТМ спасает вас от всей этой боли.

mikera
источник