将互斥体应用于erlang示例 [英] Applying a mutex into an erlang example
问题描述
WRONG
/ pre>
get_bal.A 0→get_bal.B 0→set_bal.A 10→ set_bal.B 20 == 20
RIGHT
get_bal.A 0→set_bal.A 10→get_bal.B 10→set_bal.B 30 == 30
我的代码如下:
-module银行)。
-export([account / 1,start / 0,stop / 0,deposit / 1,get_bal / 0,set_bal / 1])。
帐户(余额) - >
接收
{set,NewBalance} - >
account(NewBalance);
{get,From} - >
从! {余额,余额},
帐户(余额);
停止 - > ok
结束。
start() - >
Account_PID =产生(银行,帐户,[0]),
注册(account_process,Account_PID)。
stop() - >
account_process!停止,
注销(account_process)。
set_bal(B) - >
account_process! {set,B}。
get_bal() - >
account_process! {get,self()},
接收
{balance,B} - > B
结束。
存款(金额) - >
OldBalance = get_bal(),
NewBalance = OldBalance + Amount,
set_bal(NewBalance)。
我想知道有人可以用简短的注释来实现互斥体来解释你的思考过程。会是一个巨大的帮助!再次感谢
解决方案如果您正确使用帐户进程的邮件队列可以提供您寻求的效果。例如,您的
存款/ 1
函数有问题,因为它执行读 - 修改 - 写,其中读写是两个单独的操作。因为它们是分开的,它们允许其他不相关的动作潜入他们之间,并打破你在帐户之外执行的数学。
为什么不让帐户做自己的数学?毕竟,该账户持有资金,所以帐户外的帐户计算是没有意义的。
(余额) - >
收到
{deposit,Amount,From} - >
NewBalance =余额+金额,
从! {deposit,Amount,NewBalance},
account(NewBalance);
{withdraw,Amount,From} when Amount>余额 - >
从! {错误,{不足_金额,金额,余额}},
帐户(余额);
{withdraw,Amount,From} - >
NewBalance =余额 - 金额,
从! {withdraw,Amount,NewBalance},
account(NewBalance);
{get,From} - >
从! {余额,余额},
帐户(余额);
停止 - > ok
结束。
使用这种方法,
deposit / 1
just以原子方式增加资金并返回新的余额:存款金额(金额)金额> 0 - >
account_process! {deposit,amount,self()},
收到
{存款,金额,NewBalance} - >
{ok,NewBalance}
结束。
同样,
withdraw / 1
只是减去资金如果可能的话,如果可能的话返回新余额,或者如果发生透支,则返回错误:提取(金额)金额> ; 0 - >
account_process! {withdraw,Amount,self()},
接收
{withdraw,Amount,NewBalance} - >
{ok,NewBalance};
错误 - >
错误
结束。
get_bal / 0
函数保持不变
使用这种方法,所有交易都是原子的。
I currently have a simple bank account written using erlang, I wish to add a mutex into it so that two deposits cannot be made where the set/get balance can be interupted so that the end value is wrong for example bal A = 10 bal B = 20:
WRONG get_bal.A 0 → get_bal.B 0 → set_bal.A 10 → set_bal.B 20 == 20 RIGHT get_bal.A 0 → set_bal.A 10 → get_bal.B 10 → set_bal.B 30 == 30
My code is as follows:
-module(bank). -export([account/1, start/0, stop/0, deposit/1, get_bal/0, set_bal/1]). account(Balance) -> receive {set, NewBalance} -> account(NewBalance); {get, From} -> From ! {balance, Balance}, account(Balance); 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. deposit(Amount) -> OldBalance = get_bal(), NewBalance = OldBalance + Amount, set_bal(NewBalance).
I was wondering if someone could implement the mutex with brief annotations as to explain your thought process. Would be a huge help! Thanks again
解决方案The message queue of the account process can provide the effect you seek if you use it correctly. For example, your
deposit/1
function has problems because it performs a read-modify-write, where the read and write are two separate actions. Because they're separate, they allow other unrelated actions to sneak in between them and break the math you're performing outside the account.Why not instead make the account do its own math? After all, the account holds the funds, so it doesn't make sense to do the account calculations outside the account.
account(Balance) -> receive {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); {get, From} -> From ! {balance, Balance}, account(Balance); stop -> ok end.
With this approach,
deposit/1
just adds funds atomically and returns the new balance:deposit(Amount) when Amount > 0 -> account_process ! {deposit, Amount, self()}, receive {deposit, Amount, NewBalance} -> {ok, NewBalance} end.
Similarly,
withdraw/1
just subtracts funds atomically if possible, returning the new balance, or returns an error if an overdraft would occur:withdraw(Amount) when Amount > 0 -> account_process ! {withdraw, Amount, self()}, receive {withdrawal, Amount, NewBalance} -> {ok, NewBalance}; Error -> Error end.
The
get_bal/0
function remains the same.With this approach, all transactions are atomic.
这篇关于将互斥体应用于erlang示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!