Part V: 同期と排他制御¶
概要¶
本章では、Clojure の STM(Software Transactional Memory)を学びます。
Ref と dosync¶
;; ref の作成
(def balance (ref 1000))
;; トランザクション内で更新
(dosync
(alter balance + 100))
;; 値を取得
@balance ;; => 1100
BankAccount 実装¶
口座作成¶
(defn create-account
"銀行口座を作成"
[id initial-balance]
{:id id
:balance (ref initial-balance)})
(defn get-id [account] (:id account))
(defn get-balance [account] @(:balance account))
入出金¶
(defn deposit!
"入金"
[account amount]
(dosync
(alter (:balance account) + amount)))
(defn withdraw!
"出金(残高チェック付き)"
[account amount]
(dosync
(if (>= @(:balance account) amount)
(do
(alter (:balance account) - amount)
true)
false)))
振込(デッドロックフリー)¶
(defn transfer!
"振込(STM によるデッドロックフリー)"
[from to amount]
(dosync
(if (>= @(:balance from) amount)
(do
(alter (:balance from) - amount)
(alter (:balance to) + amount)
true)
false)))
STM の特徴¶
| 特徴 | 説明 |
|---|---|
| 自動リトライ | 競合時に自動的にリトライ |
| デッドロックフリー | ロック順序の問題なし |
| 一貫性 | トランザクション内は一貫 |
| 分離性 | 他のトランザクションから分離 |
並行テスト¶
(let [a1 (create-account 1 1000)
a2 (create-account 2 1000)
f1 (future (dotimes [_ 50] (transfer! a1 a2 1)))
f2 (future (dotimes [_ 50] (transfer! a2 a1 1)))]
@f1 @f2
(+ (get-balance a1) (get-balance a2)))
;; => 2000(常に合計金額が保持される)
次のステップ¶
Part VI では、ノンブロッキング I/O を学びます。