gen_fsm

Vance Shipley <>
Fri Jun 22 21:38:05 CEST 2001


> It's firday afternoon and I'm getting a bit impatient with the code (see
> attachment). It's a simple instantiation of the 'gen_fsm' behaviour.
> Could somebody please tell me what I am doing wrong?

As has already been pointed out, you needed to export the functions which
need to be called by outside modules.  This includes those that the gen_fsm
module must call.  I like to do it this way:

% export the callbacks common to gen_fsm behaviours
-export([init/1, code_change/4, handle_event/3,
      handle_sync_event/4, handle_info/3, terminate/3]).

% export the callbacks for (gen_fsm behaviour) states in this module
-export([sleeping/2, eating/2, working/2]).

% export the API functions
-export([start/0, letsEat/0, letsWork/0, letsSleep/0,
	printState/0, stop/0]).


> Besides that, I have a more fundamental question:  If I am not mistaken,
> the implementation of gen_fsm implies that one or more processes are
> spawned.  My question is whether it is a good idea to keep this issue
> transparent from the user who is using the behaviour.  Doesn't this
> influence the performance of his implementation?  How efficient is a
> behavriour with respect to inheritance in an onject oriented program in
> which the same design pattern is implemented?


In fact there is only one process involved.  The documentation can be a
little misleading as it shows what appears to be a message flow between
processes:

Callback module                            gen_fsm
----------------                            -------
gen_fsm:start_link                 ----->   start a new fsm process
Module:init/1                     <-----
                                            looping

gen_fsm:send_event                ----->
Module:StateName/2                <-----

.....


However the introduction to this diagram says:

	"The relationship between the generic interface functions
	 (and received messages) and the callback functions can be
	 illustrated as follows:"

Really this just shows the flow of execution which involves both your
module (fsmkvo.erl) and the gen_fsm.erl module which implements the
behaviour.  gen_fsm.erl contains the main loop of the resulting program.

You end up with one process which is executing code from both modules.
There are not any messages being sent other than when your other modules
execute gen_fsm:send_event/2 to send an event (message) into the state
machine.

The above diagram does however muddy the waters a bit 'cause it puts
the 'gen_fsm:send_event' under the 'Callback Module' column.  This
isn't how you've done it.  In your case you have an API function
(e.g. letsEat/0) which will be called by a user (e.g. the shell user).

Here we're running a shell to play with your code. The PID of the
shell process is <0.39.0>.

	1> self().
	<0.39.0>

We use your API function to start the gen_fsm process which now runs
as PID <0.36.0> (and which you have registered with the name "fsmkvo").

	2> fsmkvo:start().
	{ok,<0.36.0>}

Now we use your API function to change the state:

	3> fsmkvo:letsEat().
	ok

When we do this the shell process sources your module (fsmkvo.erl) to
get the code for the start function.  The shell process now executes
this code.  You defined letsEat/0 as:

	letsEat() ->
		gen_fsm:send_event(fsmkvo, {eat}).

In turn the shell now calls gen_fsm:send_event/2 which is defined as:

	send_event(Name, Event) ->
		Name ! {'$gen_event', Event},
		ok.

So the shell process is really doing:

	3> fsmkvo ! {'$gen_event', {eat}}.

It is sending a message to your process.  Since you included the gen_fsm
behaviour your process includes both your code (fsmkvo.erl) and the code
in gen_fsm.erl.  The gen_fsm.erl module contains the code to handle
receiving messages.  The gen_fsm code runs your code to handle the
implementation specific stuff.


	-Vance

Vance Shipley
Motivity Telecom Inc.
Tel: +1 519 579 5816





More information about the erlang-questions mailing list