Хорошо. Давайте снова запустим ваш код.
1> c(st). % compile your code
{ok,st}
% Before doing anything. let's get count of all ETS tables using ets:all/0
2> length(ets:all()).
16 % So the Erlang VM has 16 tables after starting it
3> st:start_state_maintainer().
true
% Let's check count of tables again:
4> length(ets:all()).
17 % Your process has created its own table
5> st:lookup_state().
[]
% Check count of tables again
6> length(ets:all()).
18 % Why????
7> st:update_state(fun (St) -> {testing, myval} end).
{true,{testing,myval}}
8> length(ets:all()).
19
9> st:all_state().
[]
10> length(ets:all()).
20
Итак, в строке 5 в функции maintain_state/0
вы создаете таблицу ETS, а в строках 9, 14 и 17 вы снова вызываете эту функцию! Поэтому после получения каждого сообщения (кроме void
) вы создаете новую таблицу ETS!
Давайте посмотрим на эти таблицы:
11> P = whereis(state). % Get process id of 'state' and assign it to P
<0.66.0>
12> Foreach =
fun(Tab) ->
case ets:info(Tab, owner) of
P -> % If owner of table is state's pid
io:format("Table ~p with data ~p~n"
,[Tab, ets:tab2list(Tab)]);
_ ->
ok
end
end.
#Fun<erl_eval.6.118419387>
13> lists:foreach(Foreach, ets:all()).
Table 28691 with data []
Table 24594 with data []
Table 20497 with data [{testing,myval}]
Table 16400 with data []
ok
И после уничтожения вашего процесса у нас снова должно быть 16 таблиц:
14> exit(P, kill).
true
15> length(ets:all()).
16
У вас есть два варианта. Вы можете использовать именованные таблицы следующим образом:
maintain_state() ->
% With 'named_table' option, we can use the name of table in code:
Tab = ets:new(state, [set, named_table]),
maintain_state2().
maintain_state2() ->
receive
{Pid, lookup, Key} ->
Pid ! ets:lookup(state, Key), % I used name of table
maintain_state2();
...
Или используйте таблицу в качестве аргумента maintain_state2
:
maintain_state() ->
Tab = ets:new(state, [set]),
maintain_state2(Tab).
maintain_state2(Tab) ->
receive
{Pid, lookup, Key} ->
Pid ! ets:lookup(Tab, Key),
maintain_state2(Tab);
...
Я изменил код на один из приведенных выше примеров, и вот результат:
1> st:start_state_maintainer().
true
2> st:lookup_state().
[]
3> st:update_state(fun (St) -> {testing, myval} end).
{true,{testing,myval}}
4> st:all_state().
[{testing,myval}]
5> length(ets:all()).
17
После игры с передачей сообщений Эрланга и понимания его функциональности и его концепций, я действительно предлагаю вам изучить принципы разработки OTP и поведения OTP, такие как gen_server и использовать их вместо написания ваших собственных receive ...
и Pid ! ...
заявлений.