Let's imagine that I have the following scenario:
I have three states in a state machine coded in gen_statem with state_functions. From the state A to B I do need a trigger but I want that from state B to C I do not need, because state B is going to execute some code and then pass the machine state to state C (named Idle), to wait others inputs. Check the following picture that illustrates the state machine:
Is it possible to do this?
By now I only was able to pass state to state with a trigger.
I never used it, but I think that you can achieve this whith action.
In state 'A', when you receive command you can define in the return value of the callback both the next state 'B'
and an action that may be an event that will be inserted on top of event queue so it will be triggered as soon as you enter in 'B':
state_A({call,From},command,Data) ->
NewData = do_something(Data),
{next_state,state_B,NewData,[{next_event,cast,go_to_C},{reply,From,done}]}.
Then in state 'B' you will receive immediately the event go_to_C, and you can handle it with its own call back:
state_B(cast,go_to_C,Data) ->
NewData = other_stuff(Data),
{next_state,state_C,NewData}.
Related
I am implementing a gen_fsm using the gen_statem module and when i am trying to check its state as a handle_event_function i get the following error:
> ** exception error: {function_clause,
> {gen_statem,call,[{ok,<0.139.0>},state,0]}}
> in function gen:do_for_proc/2
> called as gen:do_for_proc({ok,<0.139.0>},#Fun<gen.0.9801092>)
> in call from gen_statem:'-call_clean/4-fun-0-'/5 (gen_statem.erl, line 637) 25> c("C:/Erlang/Genserv/fsm.erl").
Below is my code which is separated into :
-mandatory methods for the fsm to work
-api that the client can use (state change,get the state,start)
- generic handlers for when client demands something related to state
-state implementations
Module
-module(fsm).
-record(state,{
current="None",
intvCount=0,
jobCount=0
}).
-export([init/1,terminate/3,callback_mode/0,code_change/4]).
-export([state/1,start/0,hire/2,fire/2,interview/2]).
-export([sitting_home/3,interviewing/3,working/3]).
-behaviour(gen_statem).
%API
start()->
gen_statem:start_link(?MODULE,[],[]).
state(PID)->
gen_statem:call(PID,state,0).
hire(PID,Company)->
gen_statem:call(PID,{hire,Company},0).
fire(PID,Company)->
gen_statem:call(PID,{fire,Company},0).
interview(PID,Company)->
gen_state:call(PID,{intv,Company},0).
%mandatory
code_change(V,State,Data,Extra)->{ok,State,Data}.
callback_mode() ->
[state_functions,handle_event_function].
init([])->
{ok,sitting_home,#state{current="None",jobCount=0,intvCount=0}}.
terminate(Reasom,State,Data)->
void.
% Generic handlers
handle_event({call,From},state,State)->
{keep_state,State,[{reply,From,State}]};
handle_event(_,_,State)->
{keep_state,State}.
% State implementations
sitting_home({call,From},{intv,Company},State=#state{intvCount=C})->
{next_state,interviewing,State#state{intvCount=C+1},[{reply,From,"Interviewing by:"++Company}]};
sitting_home(EventType,Event,State)->
handle_event(EventType,Event,State).
interviewing({call,From},{rejected,Company},State)->
{next_state,sitting_home,State,[{reply,From,"rejected by:"++Company}]};
interviewing({call,From},{accepted,Company},State=#state{jobCount=J})->
{next_state,
working,
State#state{jobCount=J+1,current=Company},
[{reply,From,"accepted offer from:"++Company}]
};
interviewing(EventType,Event,State)->
handle_event(EventType,Event,State).
working({call,From},{fire,Company},State=#state{current=C})->
{next_state,working,State#state{current="None"},[{reply,From,"Got fired from"++Company}]};
working(EventType,Event,State)->
handle_event(EventType,Event,State).
Usage
FSM_PID=fsm:start().
fsm:state(PID). //crashes when demanding state
fsm:hire(PID,"Some Company").
fsm:start() returns the tuple {ok,Pid}. You cannot use directly the return of the function in your next call. Instead you must do something like:
{ok,P} = fsm:start().
fsm:state(P).
Then you will experience other troubles, the first one is that you specify a timeout of 0, so you will get a timeout error. You will have to change this, and continue debugging :o)
[edit]
You don't need to specify the Pid, it is done in background by the gen_statem code, the gen_statem:call function is executed in the caller context so it still has access to the caller Pid.
In fact it is a little more complex, depending if you specify a timeout or not, the gen_statem:call/3 will spawn a process to call the gen:call/4 function or will directly call it, thus the Pid sent to the state machine will be either the spawned function's one or the caller's one.
The gen:call/4 also add a Reference in the message to the state machine to "sign" the answer and guaranty that an incoming message from any other part of the application will not be interpreted as the answer.
This is a general pattern in erlang (and programming) to hide as much as possible the system mechanism in interface function. Just as you do in the function state/1
In this program, I cannot for the life of me figure out how to access the value of the counter in a process.
-module(counter).
-export([start/0,loop/1,increment/1,value/1,stop/1]).
%% First the interface functions.
start() ->
spawn(counter, loop, [0]).
increment(Counter) ->
Counter ! increment.
value(Counter) ->
Counter ! {self(),value},
receive
{Counter,Value} ->
Value
end.
stop(Counter) ->
Counter ! stop.
%% The counter loop.
loop(Val) ->
receive
increment ->
loop(Val + 1);
{From,value} ->
From ! {self(),Val},
loop(Val);
stop -> % No recursive call here
true;
Other -> % All other messages
loop(Val)
end.
I assume it's:
{From,value} ->
From ! {self(),Val},
loop(Val);
which returns the value of the counter, but every time I use PID ! {PID,value}, or something similar to that it returns the thing after !, e.g. {<0.57.0>, value}.
TL;DR
You shouldn't use ! operator explicitly, it is considered an anti-pattern. You could run into some problems with typos in atoms or some bad data, just like you did this time.
To ensure correct communication with you one usually create some wrapper functions witch handle correct data format and communication with process. Function just like increment/1 value/1 and stop/1. In fact if you would use those, you would get expected results; in your case, assuming that PID is your counter, just call counter:value(PID).
Let me explain
There are few thing you seem to getting little bit wrong.
First of all ! will send message to another process. And that's all it does. Since everything in Erlang is expression (needs to return something, have a value) each call to ! will return right hand side of !. PID ! ok. will return ok, no matter what (there is slight chance that it will fail, but lets no go there). You send your message, and go on with your life, or execution.
Than, some process after receiving your message might decide to send you some message back. In case of {From, value} it will, in case of increment it wont. If you are expecting to get message back you need to wait for it and retrieve it from your mailbox. receive clause will do both waiting and retrieving. So if you decise to use ! on your own you should fallow it with receive with correct pattern match. You can see that value/1 function does just that.
Third thing is correct use of process ID's. I guess you started your counter correctly and you have it's Pid, and you can send messages to it with !. But if you expect it to send something back it needs to know your process ID, your address if you will. So you should have called PID ! {MyPid, values}. How to get MyPid? With self() function. Again, just like in value/1 function.
And last thing many people get wrong at the begging. counter module is just a file with some functions, it's not whole actor/process, and it's not an object. Fact that some value/1 and stop/1 are implemented in it, it doesn't mean that they will be run on counter actor/process. They are functions like any other, and if you call them they will be evaluated in your actor/process, on your stack (same goes for calling them from shell, shell is just another actor). You can spawn new process and tell it to run loop/1 function, but that's all it does. All increment/1 value/1 and stop/1 calls will be executed "on your side".
If this is somewhat confusing try to imagine some simpler function inside counter module, like
add(A, B) ->
A + B.
You can execute it from shell even without any counter process started. It will be created in your process, on your stack, it will add two numbers and return result.
This is important because when you call counter:value(Counter). it will execute Counter ! {self(),value}, "on your side", on your process, so self() will return Pid of your process, not the Pid of counter.
In theory you don't need to know this if you are just using those wrapper function (API or interface if you will), but since you are learning Erlang I would guess you will soon have to write such wrapper. Understanding what happens where is crucial then. Just remember that there is no magic in modules, no secret binding or special execution. Those are just plain old functions and they will be behaving just like in any other language. Only spawn, receive and maybe ! are little different.
I'm getting started with Erlang, and could use a little help understanding the different results when applying the PID returned from spawn/3 to the process_info/1 method.
Given this simple code where the a/0 function is exported, which simply invokes b/0, which waits for a message:
-module(tester).
-export([a/0]).
a() ->
b().
b() ->
receive {Pid, test} ->
Pid ! alrighty_then
end.
...please help me understand the reason for the different output from the shell:
Example 1:
Here, current_function of Pid is shown as being tester:b/0:
Pid = spawn(tester, a, []).
process_info( Pid ).
> [{current_function,{tester,b,0}},
{initial_call,{tester,a,0}},
...
Example 2:
Here, current_function of process_info/1 is shown as being tester:a/0:
process_info( spawn(tester, a, []) ).
> [{current_function,{tester,a,0}},
{initial_call,{tester,a,0}},
...
Example 3:
Here, current_function of process_info/1 is shown as being tester:a/0, but the current_function of Pid is tester:b/0:
process_info( Pid = spawn(tester, a, []) ).
> [{current_function,{tester,a,0}},
{initial_call,{tester,a,0}},
...
process_info( Pid ).
> [{current_function,{tester,b,0}},
{initial_call,{tester,a,0}},
...
I assume there's some asynchronous code happening in the background when spawn/3 is invoked, but how does variable assignment and argument passing work (especially in the last example) such that Pid gets one value, and process_info/1 gets another?
Is there something special in Erlang that binds variable assignment in such cases, but no such binding is offered to argument passing?
EDIT:
If I use a function like this:
TestFunc = fun( P ) -> P ! {self(), test}, flush() end.
TestFunc( spawn(tester,a,[]) ).
...the message is returned properly from tester:b/0:
Shell got alrighty_then
ok
But if I use a function like this:
TestFunc2 = fun( P ) -> process_info( P ) end.
TestFunc2( spawn(tester,a,[]) ).
...the process_info/1 still shows tester:a/0:
[{current_function,{tester,a,0}},
{initial_call,{tester,a,0}},
...
Not sure what to make of all this. Perhaps I just need to accept it as being above my pay grade!
If you look at the docs for spawn it says it returns the newly created Pid and places the new process in the system scheduler queue. In other words, the process gets started but the caller keeps on executing.
Erlang is different from some other languages in that you don't have to explicitly yield control, but rather you rely on the process scheduler to determine when to execute which process. In the cases where you were making an assignment to Pid, the scheduler had ample time to switch over to the spawned process, which subsequently made the call to b/0.
It's really quite simple. The execution of the spawned process starts with a call to a() which at some point shortly afterwards will call b() and then just sits there and waits until it receives a specific message. In the examples where you manage to immediately call process_info on the pid, you catch it while the process is still executing a(). In the other cases, when some delay is involved, you catch it after it has called b(). What about this is confusing?
I am trying to use Erlang/ets to store/update various informations by pattern matching received data. Here is the code
start() ->
S = ets:new(test,[]),
register(proc,spawn(fun() -> receive_data(S) end)).
receive_data(S) ->
receive
{see,A} -> ets:insert(S,{cycle,A}) ;
[[f,c],Fcd,Fca,_,_] -> ets:insert(S,{flag_c,Fcd,Fca});
[[b],Bd,Ba,_,_] -> ets:insert(S,{ball,Bd,Ba})
end,
receive_data(S).
Here A is cycle number, [f,c] is center flag , [b] is ball and Fcd,Fca, Bd, Ba are directions and angle of flag and ball from player.
Sender process is sending these informations. Here, pattern matching is working correctly which I checked by printing values of A, Fcd,Fca..etc. I believe there is something wrong with the use of Erlang/ets.
When I run this code I get error like this
Error in process <0.48.0> with exit value: {badarg,[{ets,insert,[16400,{cycle,7}]},{single,receive_data,1}]
Can anybody tell me what's wrong with this code and how to correct this problem?
The problem is that the owner of the ets-table is the process running the start/1 function and the default behavior for ets is to only allow the owner to write and other processes to read, aka protected. Two solutions:
Create the ets table as public
S = ets:new(test,[public]).
Set the owner to your newly created process
Pid = spawn(fun() -> receive_data(S) end,
ets:give_away(test, Pid, gift)
register(proc,Pid)
Documentation for give_away/3
If I want to always send an event to the initial state of a gen_fsm when I have spawned it, where should I put that function call? Right after start_link or from the process that invoked start_link in the first place. Are there any best practices here?
If you just want to alter the state of the FSM after you start it, you might simply implement the init function for your state machine:
Reading from: http://www.erlang.org/doc/man/gen_fsm.html#Module:init-1
Whenever a gen_fsm is started using
gen_fsm:start/3,4 or
gen_fsm:start_link/3,4, this function
is called by the new process to
initialize.
Args is the Args argument provided to
the start function.
If initialization is successful, the
function should return
{ok,StateName,StateData},
{ok,StateName,StateData,Timeout} or
{ok,StateName,StateData,hibernate},
where StateName is the initial state
name and StateData the initial state
data of the gen_fsm.
Also, using the init function, you're sure about the atomicity of the two functions (start_link and init). They will both succeed or fail.
I thik it is right to send first event from the process invoking FSM start function. Or return timeout = 0 from init/1 and handle 'timeout' event in the initial state.
On the other hand, it makes races possible if your gen_fsm is a rgistered process. If that is the case I would send message to the gen_fsm process PID from init/1 befor registering.