Исправить работу модуля в erlang и дополнить код
500 руб. за проект
Необходимо исправить работу созданного erlang модуля, отвечающего за запуск и остановку процессов в eshell с различными именами. Модуль создавался согласно заданию. В приложениях сам erl файл и примерная схема работы модуля.
Текст задания:
Возможные сообщения:
Для работы с #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:
Затем запускаем множество процессов 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
Текст задания:
- Создайте модуль keylist_mgr.erl.
Создайте рекорд #state{children} который будет использоваться для сохранения состояния процесса. В #state.children будет храниться список кортежей {Name, Pid}.
- на вход получает #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 используйте модуль 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.
Затем запускаем множество процессов 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
- Файлы
Отзывы
В заказе есть исполнитель
При переводе заказа из архивного в актуальный, текущий исполнитель будет снят с задачи.
Выберите тип сделки
С безопасной сделкой вы всегда сможете вернуть средства, если что-то пойдет не так. С простой сделкой вы самостоятельно договариваетесь с исполнителем об оплате и берете на себя решение конфликтов.