【问题标题】:Erlang - Transfer between files - MUTEXErlang - 文件间传输 - MUTEX
【发布时间】:2016-12-28 09:06:37
【问题描述】:

我有这个代码来运行一个简单的银行账户。 有两种存款方式和一种测试方式来初始化账户的并行存款。

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

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

【问题讨论】:

    标签: concurrency erlang mutex


    【解决方案1】:

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

    您首先需要决定是否扩展您的 account/1 功能以在单个流程中管理多个账户,或者您是否要创建一个银行流程来管理多个“单个账户流程”,例如由一个账户标识编号和/或所有者以及与其 pid 的关联。

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

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

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

    看来这个问题是关于家庭作业或自学的,所以我让你找到一个解决方案。我希望这可以帮助你。我在这里举了一个例子,每个帐户使用一个进程,尽管我认为这不是一个好的架构;它应该管理死锁。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-06
      • 2014-06-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多