2

私は同時実行プログラミングに非常に慣れていないので、解決する必要があるデッドロックに関する小さな問題があります。

したがって、以下のこのコードでは、デッドロックが発生したと思われるものは何も出力されませんが、それがどのように発生するかはよくわかりません。

let sleepMaybe() = if (random 4) = 1 then Thread.Sleep 5

type account(name:string) =
    let balance = ref 1000
    member this.Balance = lock this <| fun () -> !balance
    member this.Name = name
    member this.Withdraw amount = balance := !balance - (sleepMaybe(); amount)
    member this.Deposit amount  = balance := !balance + (sleepMaybe(); amount)

    member this.Transfer (toAcc:account) amount = 
        lock this <| fun () ->  lock toAcc <| fun () -> toAcc.Deposit amount
                                this.Withdraw amount


let doTransfers (acc:account) (toAcc:account) () = 
    for i in 1..100 do acc.Transfer toAcc 100
    printfn "%s balance: %d  Other balance: %d" acc.Name acc.Balance toAcc.Balance

let q2main() = 
    let acc1=account("Account1") 
    let acc2=account("Account2")

    startThread (doTransfers acc1 acc2)
    startThread (doTransfers acc2 acc1)

q2main()         
4

3 に答える 3

3

インスタンス自体をロックしており、何かを転送するには両方のインスタンスをロックする必要があります。それはデッドロックのレシピです。

  • スレッド 1 が acc1 をロックして転送を開始する
  • スレッド 2 は acc2 をロックして転送を開始します
  • スレッド 1 は、acc2 のロックが解放されるのを待って、転送を完了できるようにします。
  • スレッド 2 は、acc1 のロックが解放されるのを待って、転送を完了できるようにします。

それらは、お互いがロックを無期限に解放するのを待ちます。

一度に複数のロックを取得する必要がある場合は、常に同じ順序でロックを取得してください。とはいえ、オブジェクトの責任を変更して、一度に複数のロックを必要としないように最善を尽くしてください。

たとえば、出金と入金は関連のない 2 つの別個のアクションですが、残高を変更します。ロックで残高を保護しようとしています。アカウントの残高が変更されると、そのロックを保持する意味がなくなります。さらに、他のアカウントに転送する方法を知ることは、アカウントの責任ではないことをお勧めします。

それを念頭に置いて、デッドロックを解消する変更を次に示します。

type Account(name:string) =
    let mutable balance = 1000
    let accountSync = new Object()

    member x.Withdraw amount = lock accountSync 
                                  (fun () -> balance <- balance - amount)
    member x.Deposit amount =  lock accountSync 
                                  (fun () -> balance <- balance + amount)

let transfer amount (fromAccount:Account) (toAccount:Account) =
    fromAccount.Withdraw(amount)
    toAccount.Deposit(amount)
于 2013-10-15T17:57:47.747 に答える
0

これが食事の哲学者の問題です。一般的な解決策は、ロックを取得する前にロックをソートすることです。

于 2013-10-19T01:33:41.723 に答える