[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