将互斥体应用于erlang示例 [英] Applying a mutex into an erlang example

查看:183
本文介绍了将互斥体应用于erlang示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前有一个使用erlang编写的简单的银行账户,我希望在其中添加一个互斥体,以便两个存款不能被设置/得到余额可以被中断,以便结束值是错误的,例如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
/ pre>

我的代码如下:

  -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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆