我有运行简单银行帐户的代码。 有两种存款方法和一种初始化账户平行存款的测试方法。
有人会帮我实现一个在两个帐户之间转账的功能,并添加互斥锁以防止死锁吗?
-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).
答案 0 :(得分:1)
您的帐户流程管理一个帐户,因为它是一个注册过程,您无法使用此代码管理多个帐户。
首先,您需要决定是否扩展帐户/ 1功能,以便在一个流程中管理多个帐户,或者您是否要创建一个银行流程来管理多个"单个帐户流程"例如,通过帐号和/或所有者以及与其pids的关联来识别。
然后,您必须定义用于存放,检查,撤销和转移用例的消息序列。使用同步和异步协议(我猜一些超时)可以保证数据的一致性,并避免任何死锁。
Erlang代码与C ++或java面向对象代码不同。 "方法" (实际上所有在您的account / 1函数的接收块中实现的)都在帐户进程中执行:没有并发性可以担心。对于在客户端进程中执行的接口函数(例如withdraw / 1)也是如此。
说到这一点,你可以看到deposit2 / 1的代码是安全的,因为它清楚地分离了每个角色(接口和帐户余额管理),但是deposit1 / 1是不安全的,因为接口正在对在客户端进程中,使用对服务器(帐户)进程的2次单独访问来更新余额。如果同时发出2个请求,则可能会出现余额错误:
看起来这个问题是关于家庭作业或自学,所以我让你找到一个解决方案。我希望这可以帮到你。我在这里举了一个例子,每个帐户使用一个进程,虽然我不认为它是一个很好的架构;它应该管理死锁。