2016-08-21 70 views
0

我有用於運行簡單銀行帳戶的此代碼。 有兩種存款方法和一種用於初始化平行存款到賬戶的測試方法。Erlang - 文件之間的傳輸 - MUTEX

有人能幫我實現一個功能,在2個賬戶之間轉移資金,並添加互斥鎖來防止死鎖嗎?

-module(bank). 
-export([account/1, start/0, stop/0, deposit1/1, deposit2/1, get_bal/0, set_bal/1, withdraw/1]). 

%test 

-export ([test/3,user/3]). 

account(Balance) -> 
receive 
    {set, NewBalance} -> 
     account(NewBalance); 
    {get, From} -> 
     From ! {balance, Balance}, 
     account(Balance); 
    {deposit, Amount, From} -> 
     NewBalance = Balance + Amount, 
     From ! {deposit, Amount, NewBalance}, 
     account(NewBalance); 
    {withdraw, Amount, From} when Amount > Balance -> 
     From ! {error, {insufficient_funds, Amount, Balance}}, 
     account(Balance); 
    {withdraw, Amount, From} -> 
     NewBalance = Balance - Amount, 
     From ! {withdrawal, Amount, NewBalance}, 
     account(NewBalance);  
    stop -> ok 
end. 





start() -> 
    Account_PID = spawn(bank, account, [0]), 
    register(account_process, Account_PID). 

stop() -> 
    account_process ! stop, 
    unregister(account_process). 

set_bal(B) -> 
    account_process ! {set, B}. 

get_bal() -> 
    account_process ! {get, self()}, 
    receive 
     {balance, B} -> B 
    end. 

deposit1(Amount) -> 
    OldBalance = get_bal(), 
    NewBalance = OldBalance + Amount, 
    set_bal(NewBalance). 

deposit2(Amount) when Amount > 0 -> 
    account_process ! {deposit, Amount, self()}, 
    receive 
     {deposit, Amount, NewBalance} -> 
      {ok, NewBalance} 
    end. 

withdraw(Amount) when Amount > 0 -> 
    account_process ! {withdraw, Amount, self()}, 
    receive 
     {withdrawal, Amount, NewBalance} -> 
      {ok, NewBalance}; 
     Error -> 
      Error 
    end. 


test(Nbuser, Nbdeposit, Method) -> 
    start(), 
    done = spawn_users(Nbuser,Nbdeposit,Method,self()), 
    receive_loop(Nbuser), 
    Res = (get_bal() == Nbdeposit*Nbuser), 
    stop(), 
    Res. 

spawn_users(0,_Nbdeposit,_Method,_Pid) -> done; 
spawn_users(Nbuser,Nbdeposit,Method,Pid) -> 
    spawn(?MODULE,user,[Nbdeposit,Method,Pid]), 
    spawn_users(Nbuser-1,Nbdeposit,Method,Pid). 

receive_loop(0) -> done; 
receive_loop(N) -> 
    receive 
     end_deposit -> receive_loop(N-1) 
    end. 

user(0,_,Pid) -> 
    get_bal(), % to be sure that with method deposit1, the last set_bal is processed 
    Pid ! end_deposit; 
user(N,Method,Pid) -> 
    ?MODULE:Method(1), 
    user(N-1,Method,Pid). 

回答

1

您的帳戶流程管理一個單一帳戶,因爲它是一個註冊過程,您無法使用此代碼管理多個帳戶。

您需要先決定是否擴展您的賬戶/ 1功能以在單個流程中管理多個賬戶,或者您想創建一個銀行流程來管理多個「單一賬戶流程」,例如通過帳號和/或所有者以及與其pid的關聯。

然後您將不得不定義用於存入,檢查,撤銷和傳輸用例的消息序列。使用同步和異步協議(我猜有些超時)可以保證數據的一致性,避免死鎖。

Erlang代碼不同於C++或面向對象的Java代碼。 「方法」(實際上全部在您的賬戶/ 1函數的接收塊中實現)在賬戶過程中執行:沒有併發擔心存在。接口函數(如在客戶端進程中執行的撤銷/ 1)也是如此。

說了這樣的話,您可以看到,由於存款賬戶的每個角色(界面和賬戶餘額管理)都有明確的分離,所以存款賬戶2/1的代碼是安全的,但是存款賬戶1/1是不安全的,餘額在客戶端進程中使用2次單獨訪問服務器(帳戶)進程來更新餘額。如果2個請求在同一時間快到了,你可能有一個平衡的錯誤:

race condition with the deposit1 method. diagram made with "plantuml"

它看起來像這樣的問題是關於家庭作業或自學,所以我讓你找到一個解決方案。我希望這可以幫助你。我在這裏舉了一個例子,每個帳戶使用一個進程,但我認爲這不是一個好的體系結構;它應該管理死鎖。

account transfer use case