将互斥锁应用于erlang示例

时间:2015-02-17 03:24:45

标签: erlang mutex

我目前有一个使用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

我的代码如下:

-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).

我想知道是否有人可以通过简短的注释来实现互斥锁,以解释您的思考过程。会是一个巨大的帮助!再次感谢

1 个答案:

答案 0 :(得分:2)

如果您正确使用帐户流程,则帐户流程的消息队列可以提供您所寻求的效果。例如,您的deposit/1函数存在问题,因为它执行读取 - 修改 - 写入,其中读取和写入是两个单独的操作。因为它们是分开的,所以它们允许其他不相关的行为潜入它们之间并打破你在账户外执行的数学运算。

为什么不让帐户做自己的数学运算?毕竟,帐户持有资金,因此在帐户外进行帐户计算是没有意义的。

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.

通过这种方法,deposit/1只是原子地增加资金并返回新余额:

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

同样,withdraw/1只是在可能的情况下以原子方式减去资金,返回新余额,或者如果发生透支则返回错误:

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

get_bal/0功能保持不变。

使用这种方法,所有交易都是原子的。