Erlang - 在文件之间传输 - MUTEX

Erlang - Transfer between files - MUTEX

我有 运行 一个简单银行帐户的代码。 有两种入金方式和一种初始化平行入金到账户的测试方式。

谁能帮我实现一个在两个账户之间转账的功能,并添加互斥锁来防止死锁?

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

您的账户进程管理一个账户,因为它是一个注册进程,您不能使用此代码管理多个账户。

您首先需要决定是否要扩展 account/1 功能以在单个流程中管理多个帐户,或者您是否要创建一个银行流程来管理多个 "single account processes"例如,帐号 and/or 所有者及其 pids 的关联。

然后您将必须定义用于存款、支票、取款和转账用例的消息序列。使用同步和异步协议(我猜还有一些超时)可以保证数据的一致性,避免死锁。

Erlang 代码不同于 C++ 或 java 面向对象的代码。 "methods"(实际上都是在 account/1 函数的接收块中实现的)在帐户进程中执行:那里没有并发性。对于在客户端进程中执行的接口函数,如 withdraw/1 也是如此。

说到这里,你可以看到deposit2/1的代码是安全的,因为它对每个角色(接口和账户余额管理)进行了明确的分离,但是deposit1/1是不安全的,因为接口正在对余额进行操作,在客户端进程中,使用 2 个单独访问服务器(帐户)进程来更新余额。如果同时有2个请求过来,可能会出现余额错误:

看来这道题是关于作业或者自学的,所以让你自己想办法。我希望这可以帮助你。我在这里举了一个使用每个帐户一个进程的示例,尽管我认为这不是一个好的架构;它应该管理死锁。