[erlang-questions] example of race conditions ?

jla415 <>
Wed Aug 1 01:14:19 CEST 2007




David King-6 wrote:
> 
>> The problem is that only one process can have a certain name and what
>> happens if more then one process want a certain name?
> 
> This example is basically identical to mine (and sent a few minutes  
> before mine), so I'm glad to see that my concern about it is warranted.
> 
> What is considered "the" solution to this? To create these processes  
> before calling functions that may use them? What if you're writing a  
> module that others may use, and don't have control over their startup  
> process? Or what if a given daemon process is rarely used? It seems a  
> waste of resources to spawn it if it may never be used. Can the  
> process-table be locked? That doesn't seem very Erlang-ish either.
> 

First off let me say processes are extremely cheap and that you shouldn't be
concerned with keeping a daemon process around that may not be used.  if you
have something that needs to stay running with a registered name you should
probably be running something like a gen_server in a supervision tree which
would prevent worrying about all this stuff in the first place.

Having said all that, the way to start a process and ensure only one process
is running and registered is to first spawn the new process, then register
it inside the new process.  

spawn(fun() ->
             register(?NAME, self()),
             server_loop()
         end).

on subsequent attempts to start the process the newly spawned process will
die with badarg during the register() call which ensures only 1 process is
running at a time.  if you had done it by first spawning the process then
registering it from the parent there is a possibility of multiple processes
running. eg:

Pid = spawn(fun server_loop/0),
register(?NAME, Pid).

in the above example if ?NAME was already registered the newly created
process would continue to run in this example and the parent process would
die with badarg from the register call. Probably not what you had in mind...


if you need to do something more complicated like return the registered pid
every time you try to call a function things get a little more complicated
and you'd need to do something along the lines of the following to get
around all the little race conditions that can occur.

ensure_running() ->
   case whereis(server) of
       undefined ->
	   Parent = self(),
	   spawn(fun() ->
			 register(server, self()),
			 Parent ! {registered, self()},
			 server_loop()
		 end),
	   receive 
	       {registered, P} ->
		   P
	   after 5000 ->
		   whereis(server)
	   end;
       P ->
	   P
   end.


this version will ensure there is only 1 spawned process running and the
registered pid returned even in the case that 2 different processes try at
the same time and the initial whereis() returns undefined.  In this case the
second process to try to register itself would die and the parent would time
out and fall back to whereis to try to grab the pid from the first
successful registration. You could also use something like a monitor to
catch the exit instead of using the timeout.

So yes, while not exactly pretty it is possible to do what you are trying to
do and still remain lock free

-Jason

-- 
View this message in context: http://www.nabble.com/example-of-race-conditions---tf4194003.html#a11936940
Sent from the Erlang Questions mailing list archive at Nabble.com.




More information about the erlang-questions mailing list