Исправить работу модуля в erlang и дополнить код

500 руб. за проект
10 ноября 2023, 17:54 • 1 отклик • 25 просмотров
Необходимо исправить работу созданного erlang модуля, отвечающего за запуск и остановку процессов в eshell с различными именами. Модуль создавался согласно заданию. В приложениях сам erl файл и примерная схема работы модуля.

Текст задания:
  1. Создайте модуль keylist_mgr.erl.
    Создайте рекорд #state{children} который будет использоваться для сохранения состояния процесса. В #state.children будет храниться список кортежей {Name, Pid}.
Добавьте функцию loop/1 в модуль keylist_mgr.erl, которая:
  • на вход получает #state{};
  • ожидает сообщение;
  • обрабатывает сообщение;
  • отвечает на сообщение;
  • возвращается в состояние ожидания сообщения.

Возможные сообщения:

  • {From, start_child, Name} - Проверяет нет ли уже процесса с таким именем. Если нет то, стартует процесс {ok, Pid} = keylist:start_link(Name). Сохраняет {Name, Pid} в #state.children. Возвращает {ok, Pid} процессу From;
  • {From, stop_child, Name} - Проверяет есть ли уже процесс с таким именем. Если да то, останавливает процесс Name. Удаляет {Name, Pid} из #state.children. Возвращает результат процессу From;
  • stop - останавливает процесс;
  • {From, get_names} - Возвращает список имен из #state.children процессу From;
  • {'EXIT', Pid, Reason} - Залогируйте какой процесс завершился ошибкой.
Удалите процесс из #state.children.

Для работы с #state.children используйте модуль proplist.

Настройте trap_exit true. Мы можем изменить флаг для keylist_mgr с помощью process_flag(Flag, Value).


Пример кода:
loop(#state{children = Сhildren} = State) ->

receive

{From, start_child, Name} ->

%% Добавила новый элемент в список

%% Вернула результат

loop(NewState); %% Рекурсия

……

{'EXIT', Pid, Reason} ->

….

loop(NewState)

end.


2. Добавьте в keylist_mgr.erl функцию start/0.

start() ->



{ok, Pid, MonitorRef}.


В функции start/1:

  • Запустите процесс;
  • Зарегистрируйте его с именем ?MODULE;
  • Назначьте на него монитор;
  • В качестве результата верните Pid, MonitorRef.
Мы будем запускать 1 процесс keylist_mgr из Eshell. Который будет отвечать за запуск и остановку процессов keylist с различными именами.
Затем запускаем множество процессов keylist с различными именами.


Eshell:

Проверьте ваш pid (self/0).

Создайте keylist_mgr:

keylist_mgr:start().

Создайте 3 процесса keylist1, keylist2, keylist3

keylist_mgr ! {self(), start_child, keylist1}. - на этом моменте создании процесса возникает ошибка
3> keylist_mgr ! {self(), start_child, "keylist1"}.
{<0.85.0>,start_child,"keylist1"}
4> =ERROR REPORT==== 10-Nov-2023::19:00:43.921000 ===
Error in process <0.92.0> with exit value:
{undef,[{keylist,start_link,["keylist1"],[]},
{keylist_mgr,loop,1,[{file,"keylist_mgr.erl"},{line,15}]}]}

Отправьте сообщения процессу keylist3. С любыми данными типа {Key, Value, Comment}.

Протестируйте, что процесс keylist3 обрабатывает ваши сообщения, работает со списком и возвращает результат. Проверьте почтовый ящик вашего процесса (flush/0).

КОД МОДУЛЯ:
-module(keylist_mgr).
-export([start/0]).
-record(state, {
children = [] % Рекорд для хранения состояния процесса с полем children
}).

% Функция loop/1, обрабатывающая сообщения
loop(State) ->
receive
{From, start_child, Name} ->
% Проверка, нет ли уже процесса с таким именем
case proplists:get_value(Name, State#state.children) of
undefined ->
% Если процесса с таким именем нет, то стартуем новый
{ok, Pid} = keylist:start_link(Name),
% Добавляем новый процесс в список children
NewChildren = proplists:add(Name, Pid, State#state.children),
% Возвращаем Pid процесса вызывающему процессу
From ! {ok, Pid},
% Рекурсивный вызов loop с обновленным состоянием
loop(State#state{children = NewChildren});
_ ->
% Если процесс с таким именем уже существует, возвращаем ошибку
From ! {error, "Process with this name already exists"},
% Продолжаем ожидание новых сообщений
loop(State)
end;

{From, stop_child, Name} ->
% Проверка, существует ли процесс с таким именем
case proplists:get_value(Name, State#state.children) of
{Name, Pid} ->
% Если процесс существует, останавливаем его
ok = keylist:stop(Pid),
% Удаляем процесс из списка children
NewChildren = proplists:delete(Name, State#state.children),
% Возвращаем результат вызывающему процессу
From ! ok,
% Рекурсивный вызов loop с обновленным состоянием
loop(State#state{children = NewChildren});
undefined ->
% Если процесс с таким именем не существует, возвращаем ошибку
From ! {error, "Process with this name does not exist"},
% Продолжаем ожидание новых сообщений
loop(State)
end;

stop ->
% Останавливаем все процессы из списка children
lists:foreach(fun({_, Pid}) -> exit(Pid, normal) end, State#state.children),
% Возвращаем "ok"
ok;

{From, get_names} ->
% Получаем список имен из списка children
Names = proplists:get_keys(State#state.children),
% Возвращаем список вызывающему процессу
From ! Names,
% Рекурсивный вызов loop с обновленным состоянием
loop(State);

{'EXIT', Pid, Reason} ->
% Залогируем информацию о завершении процесса с ошибкой
io:format("Process ~p exited with reason: ~p~n", [Pid, Reason]),
% Удаляем процесс из списка children
NewChildren = proplists:delete_by_value(Pid, State#state.children),
% Рекурсивный вызов loop с обновленным состоянием
loop(State#state{children = NewChildren})
end.

% Функция для старта процесса
start() ->
process_flag(trap_exit, true),
Pid = spawn(fun() -> loop(#state{}) end),
register(?MODULE, Pid), % Регистрируем процесс с именем ?MODULE
MonitorRef = erlang:monitor(process, Pid), % Запускаем монитор
{ok, Pid, MonitorRef}. % Возвращаем Pid и MonitorRef
Файлы
Отзывы
R50 4fd6d9d9de7b34638f63f16582928bb5
Фрилансер
 
8 месяцев назад