[erlang-questions] Programming Erlang Exercise 8.11 revisited
Ladislav Lenart
lenartlad@REDACTED
Fri Oct 26 17:38:18 CEST 2007
Hello,
answers are inlined.
Justin Giancola wrote:
> Hello,
>
> Taking a look at the September mailing list
> (http://www.erlang.org/pipermail/erlang-questions/2007-September/029373.html),
> Charles asked about this problem, and although there were some
> proposed solutions, I'm afraid I don't quite understand. First, to
> reiterate the problem,
>
> "Write a function start(AnAtom, Fun) to register AnAtom as spawn(Fun).
> Make sure your program works correctly in the case when two parallel
> processes simultaneously evaluate start/2. In this case, you must
> guarantee that one of these processes succeeds and the other fails."
The proposed solution from the mail above:
start(AnAtom, Fun) ->
case whereis(AnAtom) of
undefined ->
Pid = spawn(Fun),
register(AnAtom, Pid);
true ->
true
end.
has a race condition between calls whereis/1 and register/2.
> First off, I've read elsewhere that register/2 already prevents this
> kind of thing by maintaining a queue of registration requests that it
> processes in some definite order. So you are guaranteed that two
> processes could never be registered with the same name, etc. At the
> risk of sounding naive, doesn't the following function meet the
> problem's requirements?
>
> start(AnAtom, Fun) ->
> register(AnAtom, spawn(Fun)).
With this solution, when a call to register/2 fails, it is the process
that called it who gets killed and not the newly spawned process.
> Now, a potential problem here is that the phrasing of the problem is a
> little vague. Does 'guarantee that one of these processes succeeds
> and the other fails' mean 'succeeds at registration', or 'succeeds at
> being spawned'? If it's the former, is my proposed solution adequate?
> If it's the latter, what exactly happens to the newly spawned process
> when
>
> register(AnAtom, spawn(Fun))
>
> is called after AnAtom has already been registered? Is the new
> process spawned and orphaned? Does spawning the new process fail
> somehow? Without knowing the answers to these questions, one could do
> something like:
>
> start(AnAtom, Fun) ->
> Pid = spawn(Fun),
> try register(AnAtom, Pid)
> catch
> error:_X -> {error,"atom already registered"}
> after
> Pid ! die
> end.
This works. However it requires that Fun will explicitly receive die
message and stop itself. It is also a problem if the spawned process
should not start doing anything (evaluating Fun) if it can not be
registered.
> to avoid encountering such issues. However, this doesn't seem like a
> very concurrency-oriented solution.
>
> In summary, I'm not sure I understand the intent of this problem. As
> it's the first problem on concurrent programming in the book, I don't
> think it's intended to be that difficult. On the other hand, neither
> of my approaches seems very useful. Thoughts?
I posted the following code snippet as a reply to the original post
from Charles Gordon that seemed to solve the problem for him:
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.
Hope this helps,
Ladislav Lenart
More information about the erlang-questions
mailing list