[erlang-questions] Selective receive issue

Grasl Christoph <>
Tue Aug 5 14:54:28 CEST 2008


Hi, Vlad!

Try the following:

First the loop: (can be a single registered process (better than passing PIDs around) or 
a stand alone gen_server (which has certain qualities you might wanna have in your module..)):


loop() -> 
   receive 
      {input, Data} ->
         processInput(Data), 
         loop();
      AnyMessage -> 
         store(AnyMessage),
         loop
      after 2300 ->	
         timeOutRoutine(),
	 loop()
   end.		

Then a loop-state in order to verify the loops' state and 
to store messages that are not caught by the reseive-pattern:

State = [{active, true}, {pending, []}]
 
the adapted loop function and the list-related helperz:

loop(State) -> 
   receive
       activate ->   
          NewState = replaceVariable(State, {active, true}),
          loop(NewState);
       deactivate ->
          NewState = replaceVariable(State, {active, false}),
          loop(NewState);
       {input, Data} ->
          case getValue(State, active) of 
             false -> 
                loop(State);
             true -> 
               processInput(Data), 
               loop(State)
          end;
      AnyMessage -> 
          case getValue(State, active) of 
             false -> 
                loop(State);
             true -> 
               %% now storing the msg in the loop's state:
               NewState = replaceVariable(State, {pending, AnyMessage}), 
               loop(State)
          end
      after 2300 ->	
         timeOutRoutine(),
	 loop()
   end.	

%% getValue

getValue([], Key) -> 
   value_not_found;

getValue([{Key, Value}, Rest], Key) -> 
   Value;

getValue([{_OtherKey, _OtherValue}, Rest], Key) -> 
   getValue(Rest, Key).

%% replaceVariable

replaceVariable({SuperVarKey, VarList}, {VarKey, NewValue}) ->
	{SuperVarKey, replaceVariable(VarList, {VarKey, NewValue})}; 

replaceVariable(VarList, {Key, Value}) ->
	replaceVariable(VarList, {Key, Value}, []).


replaceVariable([], {_VarKey, _NewValue}, _Acc) ->
	void;

replaceVariable([{VarKey, _OldValue} | Rest], {VarKey, NewValue}, Acc) ->
	lists:append([ lists:append([Acc, [{VarKey, NewValue}]]), Rest]);


replaceVariable([{OtherVarKey, OtherValue} | Rest], {VarKey, NewValue}, Acc) ->
	replaceVariable(Rest, {VarKey, NewValue}, lists:append([Acc, [{OtherVarKey, OtherValue}]])).


Obviously there are many ways to Rome, you can also use a dets/ets or mnesia to store wanted/unwanted messages instead of 
saving it to the loop's state. Or you could use a gen_server instead that has some additional features with a native 
server state that might suit your needs a lil' better. 

Best Regards,

Christoph Grasl
Embedded Software Entwickler

KEYTRONIX
Gesellschaft für industrielle Elektronik und Informationstechnologie mbH

Ungargasse 64-66/1/109
A-1030 WIEN

E-Mail: 
Tel.: +43 (1) 718 06 60 - 323
Mobil: +43 (664) 8556456
WWW: http://www.keytronix.com

HG Wien FN 261131t

Confidentiality Notice:
This message may contain privileged and confidential information. If you think, for any reason, that this message may have been addressed to you in error, you must not disseminate, copy or take any action in reliance on it, and we would ask you to notify us immediately by return email.



-----Ursprüngliche Nachricht-----
Von:  im Auftrag von Vlad Dumitrescu
Gesendet: Di 05.08.2008 08:59
An: erlang-questions
Betreff: [erlang-questions] Selective receive issue
 
Hi all,

I have an example of a receive where I don't seem to be able to use the
usual "dump any unrecognized messages" catch-all clause. I think it is also
an example where channels could be useful, but the main question is whether
I am missing the obvious or not.

I have a process that takes {input, Data} messages from its mailbox and
processes them (not necessarily one at a time). Flow control is implemented
as a pair of 'start'/'stop' messages. The way I implemented the main loop is
(simplified)

  receive
    start->Running = true, loop();
    stop->Running = false, loop()
  after 0 ->
      if Running -> process_one_step(), loop();
         true -> loop()
      end
  end,

where the process_one_step() function may call

  receive
    {input, Data} -> ...
  end

one or several times (it is configurable by the clients).

It seems to me that there is no place where I can put a '_->...;' clause
without creating problems. So I'd like to ask if anyone sees another way to
structure this that will allow rogue messages to be discarded.

------
A solution that requires an EEP :-) is to introduce an extension to the
receive statement that will explicitly  keep matched messages  in the
mailbox. For example

receive
  Pattern -> keep(), loop();
  Msg ->  process(Msg), loop()
end

keep() is the extension that says "leave the message in the mailbox and
proceed". This way process() will be called with all messages except those
matching Pattern

Would something like that be useful, or are there already ways to achieve
the same effect?

best regards,
Vlad

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20080805/10dc6923/attachment.html>


More information about the erlang-questions mailing list