检查并行进程是否评估相同的功能

时间:2014-04-02 22:20:53

标签: erlang

几天以来,我正在学习Erlang,使用Joe Armstrong的伟大着作Programming Erlang

我正在关注并发编程这一章,在本章的最后,还有一个问题需要解决:

  

编写函数start(AnAtom,Fun)将AnAtom注册为spawn(Fun)。   在两个并行的情况下,确保您的程序正常工作   进程同时评估start / 2。在这种情况下,你必须   保证其中一个过程成功而另一个失败。

我解决了这个问题的第一部分,确保每个进程都会生成一个不同的原子。

关于第二部分,我被卡住了,因为如果我理解正确,我找不到检查两个并行进程是否同时评估函数start/2的方法。起初,我想过一个计数器检查进程产生的数量,但我无法理解如何执行此检查。我在this thread找到了一些有趣的东西(来自OOP背景,我考虑过Singleton模式),但我不确定用计数器读取和写入文件是否是执行此检查的最佳方法。我认为有一种简单的方法可以做到这一点。

我写的代码如下:

-module(probl).
-export([start/2,stop/1]).

start(Atom,Fun) ->
% check here counter value
case isUniqueProcess(Times) of % here I'm trying to use a counter, but I'm stuck..
    true ->
        Pid = spawn(fun() -> doSomething(Atom,Fun) end), 
        register(Atom,Pid);
    false ->
        io:format("Sorry, no more processes to spawn."),
        void
end.    

stop(Atom) -> 
    case whereis(Atom) of
        undefined -> void;
        Pid -> io:format("Stopped."), Pid ! stop
    end.

isUniqueProcess(Times) -> % here I should increment the counter, but how?
    if
        Times =:= 0 ->
            true;
        Times > 0 ->
            false
    end.

doSomething(Atom,Fun) ->
    receive
        stop -> void
    after 15000 ->
        Fun(),
        doSomething(Atom,Fun)
    end.

对我来说,来自强大的OOP背景,转换另一种编程思维并不是那么容易,就像它在Erlang中发生的那样,也许这就是我遇到困难的原因。我该如何解决这个问题?

3 个答案:

答案 0 :(得分:2)

您可以尝试使用此代码。

start(Atom, Fun) when is_atom(Atom), is_function(Fun, 0) ->
    Sender = self(),
    Fun2 = fun() ->
           case catch register(Atom, self()) of
               true ->
               Sender ! {started, self()},
               Fun();
               _ ->
               Sender ! {already_running, self()}
           end
       end,
    Pid = spawn(Fun2),
    receive
    {started, Pid} ->
        {ok, Pid};
    {already_running, Pid} ->
        already_running
    end.

答案 1 :(得分:2)

如果两个或更多进程尝试以相同的名称注册,那么只有第一个进程才会成功。以下将在尝试注册时生成错误。在这种情况下,仅仅让后续进程崩溃是不够的?为此,必须在已启动的过程中完成注册。

如果您不想让进程崩溃,可以将进程包装在catch中并终止并使用exit(normal)显式终止它。

答案 2 :(得分:1)

使用rvirding方法:

start(AnAtom, Fun) ->
  spawn(fun() -> register(AnAtom, self()), Fun() end).

或者:

start(AnAtom, Fun) ->
  spawn(fun() -> case catch register(AnAtom, self()) of true -> Fun(); _ -> ok end end).
相关问题