[erlang-questions] Teaching Erlang as part of a paper -- advice sought

Richard O'Keefe ok@REDACTED
Wed Feb 10 02:54:16 CET 2010


On Feb 9, 2010, at 9:36 PM, Ulf Wiger wrote:

> Richard O'Keefe wrote:
>> On Feb 8, 2010, at 10:33 PM, Ulf Wiger wrote:
>>> Kostis has alreay mentioned that data races are possible in Erlang.
>> I am dusting off my old 'pid_name' proposal from the 90s and turning
>> it into an EEP.  I'd like to avoid races in the core language.
>
> Some of the issues in the EEP were also dealt with in my gproc
> paper (http://portal.acm.org/citation.cfm?id=1292522, also
> http://svn.ulf.wiger.net/gproc/trunk/gproc/doc/erlang07-wiger.pdf).

I'm familiar with that paper.
gproc and my EEP solve opposite problems.
gproc answers the question "given a large number of processes that
WANT to be found, how do you do that?" (and a bunch of other questions).
My EEP answers the question "given a module with one or more private
processes that need to be findable by and only by the interface
functions of the module, how do you do _that_?"

> I solved the race problem on registration by only allowing a
> process to register itself. There is still a race in the sense
> that two processes may contend for the same name, or that a
> registered process may die before a "registered send" is delivered,
> but this is, I think, an unavoidable part of the semantics of
> referring to processes by name, combined with dynamic typing
> and asynchronous message passing.

Let's stick with the old interface for a second or two.

start() ->
     case whereis(server)
       of undefined ->
          register(server, spawn(fun () ->
	     loop([])
          end))
        ; Pid when is_pid(Pid) ->
	 ok
     end.

Now let's move the register/1 call inside the new process.

start() ->
     case whereis(server)
       of undefined ->
          spawn(fun () ->
              register(server, self()),
              loop([])
          end)
        ; Pid when is_pid(Pid) ->
          Pid
     end.

In the first version, the caller of start/1 knows that there is
a time between the entry to that function and the exit from it
when there was a process registered as 'server'.  In the second
version, the caller does not know that.  We fix _that_ by doing

start() ->
     case whereis(server)
       of undefined ->
          Client = self(),
          Secret = make_ref(),
          Pid = spawn(fun () ->
              register(server, self()),
              Client ! Secret,
              loop([])
          end),
          receive Secret -> Pid end
        ; Pid when is_pid(Pid) ->
          Pid
     end.

Now, of course, if two processes both call start/1, one of the
new server processes will crash, and its client will be left waiting
forever.  So now we have to allow for that.

start() ->
     case whereis(server)
       of undefined ->
          Client = self(),
          Secret = make_ref(),
          spawn(fun() ->
              case catch register(server, self())
                of true ->
                   Client ! {Secret,Pid}
	          loop([])
                 ; {'EXIT',_} ->
                   Client ! {Secret,undefined}
              end
          end),
          receive
              {Secret,undefined} ->
                  sleep(500),
                  start()
	   ; {Secret,Pid} when is_pid(Pid) ->
		 Pid
	 end
        ; Pid when is_pid(Pid) ->
	 Pid
     end.

What am I missing?  How does only allowing a process to register
itself eliminate the race?  The race is a race for access to the
registry entry.

The thing about pid_name_spawn{,_link}/2 is that (encapsulated)
registration done that way doesn't even begin a second process
is another registration is under way.  There _is_ locking going on
in the implementation of the registry already, it's just the
classic Java "synchronized doesn't span _two_ operations" bug.


We can deal with some of the other issues, like the possibility
of a registered process dying inconveniently by programming it so
that it WON'T die; anything risky being shoved off onto a new
support process (and that way lies supervision, though you need
not press it _quite_ that far).  But it is far easier to make
the registered process stay alive if it can't get forged messages.
Which means not using the registry.

> On the topic of the process registry, there is also some recent
> QuickCheck work that might be of interest.
>
> Claessen, K., Palka, M., Smallbone, N., Hughes, J., Svensson, H.,  
> Arts, T., and Wiger, U. 2009. Finding race conditions in Erlang with  
> QuickCheck and PULSE. SIGPLAN Not. 44, 9 (Aug. 2009), 149-160. DOI= http://doi.acm.org/10.1145/1631687.1596574

Note the key sentence:
   "Our approach is based on property-based testing using  
QuickCheck ...,
    in a commercial version for Erlang developed by Quviq AB ..."
         ^^^^^^^^^^

This is not a whine by an academic about not being able to get stuff  
free.
I do have some research funding, and the department has some "equipment"
money.  But there is one thing I absolutely totally expect to find at a
commercial web site, and that is PRICES.  I spent about $200 of billable
time searching the http://www.quviq.com/ web site in vain for any hint  
of
their prices.  I can only conclude that while QuickCheck for Erlang is
commercial and proprietary, it is no longer for sale, otherwise they
would be making some kind of effort to sell it.  Either that, or the
prices are so high that they are worried about scaring customers off.
(Yes, I saw the free 30-day trial, but the link is dead.)




More information about the erlang-questions mailing list