spawn without linking?

Sean Hinde <>
Thu Apr 29 21:04:10 CEST 2004


>>
>
> Ah, but Joe, you changed the semantics. Sean had a timeout argument,
> which you don't.  ;-)
>
> BTW, Sean, you should rethink the implementation of the timeout.
> I think it's better to start a timer and handle a timeout message.
> In your present implementation, the "timer" will restart anytime
> one of the servers responds, making it fuzzy what the timeout
> really means.
>


OK, again !  I kept the foldl to emphasise that we visit each sent
call exactly once while gathering results, so it has grown somewhat with
the addition of a second state.

%% @doc Call one or more gen_servers multiple times with different
%% queries concurrently. This is equivalent to calling
%% gen_server:call(Name, Request, Timeout) multiple times except that
%% they are handled concurrently.
%% </p>
%% It is assumed that the calling process can tolerate late result
%% messsages arriving after this routine has finished.
%%
%% @spec multi_call(Requests, Timeout::integer()) ->
%%          {[{Name, Result}], [Failure]}
%% Requests = [{Name, Request}]
%% Name = pid() | atom()
%% Request = term()
%% Result = term()
%% Failure = pid() | atom()
multi_call(Requests, Timeout) when is_list(Requests), 
is_integer(Timeout) ->
     Mrefs = lists:map(fun({Name, Req}) ->
                               Mref = erlang:monitor(process, Name),
                               Name ! {'$gen_call', {self(), Mref}, Req},
                               {Name, Mref}
                       end, Requests),
     Timer = erlang:start_timer(Timeout, self(), timeout),
     Res = lists:foldl(
             fun({Name, Mref}, {within_time, Succ, Fail}) ->
                     receive
                         {Mref, Reply} ->
                             demonitor(Mref),
                             {within_time, [{Name, Reply}|Succ], Fail};
                         {'DOWN', Mref, _, _, _} ->
                             {within_time, Succ, [Name|Fail]};
                         {timeout, Timer, timeout} ->
                             demonitor(Mref),
                             {outside_time, Succ, [Name|Fail]}
                     end;
                ({Name, Mref}, {outside_time, Succ, Fail}) ->
                     receive
                         {Mref, Reply} ->
                             demonitor(Mref),
                             {outside_time, [{Name, Reply}|Succ], Fail};
                         {'DOWN', Mref, _, _, _} ->
                             {outside_time, Succ, [Name|Fail]}
                     after 0 ->
                             demonitor(Mref),
                             {outside_time, Succ, [Name|Fail]}
                     end
             end, {within_time, [],[]}, Mrefs),
     case Res of
         {within_time, Succ, Fail} ->
             erlang:cancel_timer(Timer),
             receive
                 {timeout, Timer, timeout} ->
                     {Succ, Fail}
             after 0 ->
                     {Succ, Fail}
             end;
         {outside_time, Succ, Fail} ->
             {Succ, Fail}
     end.

demonitor(Mref) ->
     erlang:demonitor(Mref),
     receive
         {'DOWN', Mref, _, _, _} ->
             ok
     after 0 ->
             ok
     end.





More information about the erlang-questions mailing list