Сопоставление сообщения, полученного состоянием в gen_statem в Erlang
У меня проблема с сопоставлением сообщения, полученного в татеме gen_s в модуле Erlang, который я назвал e_counter. Вот снимок кода. gen_statem связан с супервизором. Когда процесс e_counter получает сообщение о событии от другого процесса, он увеличивает счетчик. Счетчик реализован в виде записи, которая выглядит так
-record(cntr, {cnt :: non_neg_integer(),
iv :: non_neg_integer()}).
И определяется так
CV = InitValues#initValues.di_CV,
Cntr = #cntr{cnt = 0, iv = CV},
Где CV представляет значение, до которого счетчик должен считать.
Все сообщения в коде создаются с использованием записи сообщения, которая выглядит следующим образом
-record(message, {type :: event | data,
name :: atom(),
value :: any() | undefined,
ref :: reference(), % Currently not used
from :: pid()}).
Вот снимок gen_statem
incrCnt(cast, #message{type = event, name = ei_INCR, value = undefined, ref = _Ref, from = _From} =_Message, State) when State#state.cntr#cntr.cnt < State#state.cntr#cntr.iv ->
io:format("Current State ~p~n", [State]),
NewCount = State#state.cntr#cntr{cnt = State#state.cntr#cntr.cnt +1},
io:format("Count so far ~p~n", [NewCount]),
{next_state, incrCnt, NewCount};
incrCnt(cast, #message{type = event, name = ei_INCR, value = undefined, ref = _Ref, from = _From} = _Message, State) when State#state.cntr#cntr.cnt =:= State#state.cntr#cntr.iv ->
NewCount = State#state.cntr#cntr{cnt = 0},
gen_func:send_event(State#state.connections#connections.eventOut#eventOut.eo_EO),
{next_state, incrCnt, NewCount}.
В отчете об ошибках SASL, показанном ниже, при первом получении сообщения состоянием incrCnt оно правильно сопоставляется, а в состоянии incrCnt счетчик увеличивается. Однако любые сообщения, полученные после этого, приводят к ошибке, как показано в разделе ОТЧЕТ ОБ ОШИБКАХ отчета.
Eshell V13.1.4 (abort with ^G)
1> application:start(sasl).
ok
2> application:start(checkCntrApp).
{normal, }
Port #Port<0.5>
ok
3> *** Different: StateBitIndxVals: [1] ProfinetBitIndxVals *** [0]
ok ),
,ok),
Current State {state,{connections,{eventOut,{connector,ei_2,kl_2404_A}},
{dataOut}},
{cntr,0,4}}
Count so far {cntr,1,4}
*** Different: StateBitIndxVals: [0] ProfinetBitIndxVals *** [1]
ok ),
,ok),
=ERROR REPORT==== 28-Aug-2023::15:32:55.544317 ===
** State machine e_counter terminating
** Last event = {cast,{message,event,ei_INCR,undefined,
#Ref<0.4143019743.798228481.4176>,<0.104.0>}}
** When server state = {incrCnt,{cntr,1,4}}
** Reason for termination = error:function_clause
** Callback modules = [e_counter]
** Callback mode = state_functions
** Stacktrace =
** [{e_counter,incrCnt,
[cast,
{message,event,ei_INCR,undefined,
#Ref<0.4143019743.798228481.4176>,<0.104.0>},
{cntr,1,4}],
[{file,"src/e_counter.erl"},{line,115}]},
{gen_statem,loop_state_callback,11,[{file,"gen_statem.erl"},{line,1426}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,240}]}]
Как получается, что полученное сообщение сопоставляется в первый раз и никогда после этого?
1 ответ
Возвращенный кортеж состояния{next_state, incrCnt, NewCount}
переопределяет State (последнюю переменную) с помощью NewCount.
Вы напечатали NewCount, и это не структура данных State, содержащая cntr, а только cntr {cntr,1,4}.
Вторая итерация пытается получить доступ к записи состояния в Guard, но в качестве аргумента имеет NewCount, то есть запись cntr.