Knowledge Base--Handling Write Skew Anomaly処理書き込み偏差(123)

4899 ワード

ケース:2つの口座の総額が1000を超えることを確保した場合、引き出し操作を実行できます.2つの口座が同時に(concurrency)それぞれ引き出しを行う場合に問題が発生します
エラーコード:
    (def checking-balance (ref 500))
    (def savings-balance (ref 600))

    (defn withdraw-account [from-balance constraining-balance amount]
        (dosync
            (let [total-balance (+ @from-balance @constraining-balance)]
            (. Thread sleep 1000)
            (if (>= (- total-balance amount) 1000)
                (alter from-balance - amount)
            (println "Sorry, can't withdraw due to constraint violation")))))

    (println "checking-balance is" @checking-balance)
    (println "savings-balance is" @savings-balance)
    (println "Total balance is" (+ @checking-balance @savings-balance))

    (future (withdraw-account checking-balance savings-balance 100))
    (future (withdraw-account savings-balance checking-balance 100))

    (. Thread sleep 2000)

    (println "checking-balance is" @checking-balance)
    (println "savings-balance is" @savings-balance)
    (println "Total balance is" (+ @checking-balance @savings-balance))

We start with the given balances for the two accounts:
checking-balance is 500
savings-balance is 600
Total balance is 1100
checking-balance is 400
savings-balance is 500
Total balance is 900

正しいコード:
(defn withdraw-account [from-balance constraining-balance amount]
        (dosync
             (let [total-balance (+ @from-balance (ensure constraining-balance))]
            (. Thread sleep 1000)
             (if (>= (- total-balance amount) 1000)
                 (alter from-balance - amount)
                 (println "Sorry, can't withdraw due to constraint violation")))))

結果:
checking-balance is 500
savings-balance is 600
Total balance is 1100
checking-balance is 500
savings-balance is 500
Total balance is 1000
Sorry, can't withdraw due to constraint violation

秘密:On line 3,we called ensure()on the value constraining-balance,which we read but don’t modify in the transaction.At this point, STM places a read lock on that value, preventing other transactions from gaining a write lock. When the transaction nears completion, STM releases all read locks before it performs the commit. This prevents any possibility of deadlock while increasing concurrency.
Clojure STM is the aspirin of the programming concurrency world—it can remove so much pain. If we forget to create a transaction, we’re sternly rebuked For simply placing dosync at the right place, we’re rewarded with high concurrency and consistency between threads. Such low ceremony, concise, highly expressive, and very predictable behavior all make Clojure STM an option worth serious consideration.