将互斥量应用到 erlang 示例中

Applying a mutex into an erlang example

我目前有一个使用erlang编写的简单银行账户,我希望在其中添加一个互斥锁,这样就无法在set/get余额可以中断的地方进行两次存款,从而导致最终值错误示例 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).

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

账号进程的消息队列如果使用得当,可以达到你想要的效果。例如,您的 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 只需自动添加资金和 returns 新余额:

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

类似地,withdraw/1 如果可能的话,只是自动减去资金,返回新余额,或者 returns 如果发生透支则出错:

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

get_bal/0功能保持不变。

使用这种方法,所有事务都是原子的。