常に言及されるソフトウェアトランザクショナルメモリの主な利点の1つは、構成可能性とモジュール性です。異なるフラグメントを組み合わせて、より大きなコンポーネントを作成できます。ロックベースのプログラムでは、これは多くの場合当てはまりません。
これを実際のコードで示す簡単な例を探しています。 Clojureの例をお勧めしますが、Haskellも問題ありません。例が簡単に構成できないロックベースのコードも示している場合のボーナスポイント。
いくつかの銀行口座があるとします。
(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)
複数の転送はすべて単一の結合トランザクションで発生したことに注意してください。つまり、より小さなトランザクションを「構成」することができました。
ロックを使用してこれを行うには、非常に迅速に複雑になります。アカウントを個別にロックする必要があると仮定すると、デッドロックを回避するために、ロック取得順序でプロトコルを確立するなどの操作を行う必要があります。見つけにくい間違いを犯すのはとても簡単です。 STMはこのすべての苦痛からあなたを救います。