为什么werl在一个shell窗口中执行相同的代码并在另一个shell窗口中冻结?

时间:2016-08-15 18:24:10

标签: erlang erlang-shell

我正试图从O'Reilly Erlang编程书中解决练习5-2。 我的设置为Win10werl Eshell V7.3。 以下是重现我的问题的步骤:

  1. c(frequency).

  2. frequency:start().

  3. CTRL-G - > S - > C - 切换到新的Erlang shell

  4. frequency:allocate().

  5. frequency:deallocate(10).

  6. 如果我省略了第3点,那么一切顺利,但是当我按照上述程序执行所有操作时,shell会卡在行3043中。

    有人可以解释一下我做错了什么以及如何在这两种情况下获得完全相同的行为:使用一个,还有两个shell?

    模块的代码(此处有两个警告,但无论如何它都会编译,我只是在从进行分配的同一个Pid调用时才尝试进行释放):

    -module(frequency).
    -export([start/0, stop/0, allocate/0, deallocate/1]).
    -export([init/0]).
    
    %% These are the start functions used to crate and
    %% initialize the server.
    
    start() ->
      register(frequency, spawn(frequency, init, [])).
    
    init() ->
      Frequencies = {get_frequencies(), []},
      loop(Frequencies).
    
    % Hard Coded
    get_frequencies() -> [10, 11, 12, 13, 14, 15].
    
    %% The client Functions
    
    stop()          -> call(stop).
    allocate()      -> call(allocate).
    deallocate(Freq)-> io:format("Calling deallocate~n",[]), call({deallocate, Freq}).
    
    %% We hide all message passing and the message
    %% protocol in a functional interface.
    
    call(Message) ->
      Self = self(),
      io:format("Self: ~w~n", [Self]),
      frequency ! {request, Self, Message},
      receive
        {reply, Reply} -> Reply
      end.
    
    %% The Main Loop
    
    loop(Frequencies) ->
      receive 
        {request, Pid, allocate} ->
          {NewFrequencies, Reply} = allocate(Frequencies, Pid),
          reply(Pid, Reply),
          loop(NewFrequencies);
        {request, Pid2, {deallocate, Freq}} ->
          io:format("Dealocate ~w from pid ~w~n", [Freq, Pid2]),
          NewFrequencies = deallocate(Frequencies, Freq), %, Pid2),
          reply(Pid2, ok),
          loop(NewFrequencies);
        {request, Pid, stop} ->
          reply(Pid, ok)
      end.
    
    reply(Pid, Reply) ->
      Pid ! {reply, Reply}.
    
    %% The Internal Help Functions used to allocate and
    %% deallocate frequencies.
    
    allocate({[], Allocated}, _Pid) ->
      {{[], Allocated}, {error, no_frequency}};
    allocate({[Freq|Free], Allocated}, Pid) ->
      {{Free, [{Freq, Pid}| Allocated]}, {ok, Freq}}.
    
    deallocate({Free, Allocated}, Freq) -> %, Pid) ->
      Response = lists:keysearch(Freq, 1, Allocated),
      io:format("Response: ~w~n", [Response]),
      case Response of
        {value, {Freq, OPid}} ->
            case OPid of
              Pid ->
                NewAllocated = lists:keydelete(Freq, 1, Allocated),
                io:format("Removed freq~n",[]),
                {[Freq|Free], NewAllocated};
              _OtherPid ->
                io:format("Not allowed to remove freq~n",[]),
                {Free, Allocated}
            end;
        _ -> io:format("Not removed freq~n",[]), {Free, Allocated}
      end.
    

1 个答案:

答案 0 :(得分:0)

我对问题没有完整的解释,但是它与io:format的使用有关,有一个模糊的(对我来说是模糊的:o)组长的概念,用于确定哪个shell是io :format应该显示一条消息。

通常,在服务器循环中显示消息并不是一个好主意,这在服务器进程中执行,最好在调用进程中执行的接口函数中执行。

我稍微更改了你的代码,删除了无用的打印并更正了pid的测试,它在多个shell中都能正常工作。

-module(freq).
-export([start/0, stop/0, allocate/0, deallocate/1]).
-export([init/0]).

%% These are the start functions used to crate and
%% initialize the server.

start() ->
  register(frequency, spawn(freq, init, [])).

init() ->
  Frequencies = {get_frequencies(), []},
  loop(Frequencies).

% Hard Coded
get_frequencies() -> [10, 11, 12, 13, 14, 15].

%% The client Functions

stop()          -> call(stop).
allocate()      -> call(allocate).
deallocate(Freq)-> io:format("Calling deallocate~n",[]), call({deallocate, Freq}).

%% We hide all message passing and the message
%% protocol in a functional interface.

call(Message) ->
  Self = self(),
  frequency ! {request, Self, Message},
  receive
    {reply, Reply} -> Reply
  end.

%% The Main Loop

loop(Frequencies) ->
  receive 
    {request, Pid, allocate} ->
      {NewFrequencies, Reply} = allocate(Frequencies, Pid),
      reply(Pid, Reply),
      loop(NewFrequencies);
    {request, Pid, {deallocate, Freq}} ->
      {NewFrequencies,Reply} = deallocate(Frequencies, Freq, Pid),
      reply(Pid, Reply),
      loop(NewFrequencies);
    {request, Pid, stop} ->
      reply(Pid, ok)
  end.

reply(Pid, Reply) ->
  Pid ! {reply, Reply}.

%% The Internal Help Functions used to allocate and
%% deallocate frequencies.

allocate({[], Allocated}, _Pid) ->
  {{[], Allocated}, {error, no_frequency}};
allocate({[Freq|Free], Allocated}, Pid) ->
  {{Free, [{Freq, Pid}| Allocated]}, {ok, Freq}}.

deallocate({Free, Allocated}, Freq, Pid) ->
  Response = lists:keysearch(Freq, 1, Allocated),
  case Response of
    {value, {Freq, Pid}} ->
      NewAllocated = lists:keydelete(Freq, 1, Allocated),
      {{[Freq|Free], NewAllocated},removed};
    {value, {Freq, _OtherPid}} ->
      {{Free, Allocated},not_owner};
    _ ->
      {{Free, Allocated},not_found}
  end.