Exame - 17 de Julho de 2000
.gif)
-module(pergunta_1).
-export([start/0,inicio/0,multi/1,g_f/1,u/1,final/0]).
start() -> spawn(?MODULE,inicio,[]).
inicio() -> P_final=spawn(?MODULE,final,[]), P_u=spawn(?MODULE,u,[P_final]), P_multi=spawn(?MODULE,multi,[P_final]), loop(P_u,P_multi).
loop(P_u,P_multi) ->
receive
{A,B,C} -> ok
end,
P_multi ! {A,C},
P_u ! {B},
loop(P_u,P_multi).
% % apenas para que nao gere erros de compilacao % u(A) -> receive B -> B end, u(A).
multi(P_final) ->
receive
{A,C} -> ok
end,
Lista_sub=lanca_subs(length(A)),
envia_valores_sub(A,C,Lista_sub),
G=recebe_valores_sub(Lista_sub),
P_final!G.
final() ->
receive
G -> ok
end,
receive
U -> ok
end,
Lista_sub=lanca_subs(length(G)),
envia_valores_sub(G,U,Lista_sub),
F=recebe_valores_sub(Lista_sub),
io:format("Resultado final: ~w.~n",[F]).
lanca_subs(N) -> lanca_subs(N,[]). lanca_subs(0,Lista) -> Lista; lanca_subs(N,Lista) -> Pid_novo=spawn(?MODULE,g_f,[self()]), lanca_subs(N-1,[Pid_novo|Lista]).
envia_valores_sub([],_Multi_2,[]) ->
ok;
envia_valores_sub([Multi_1|Lista],Multi_2,[Pid|Lista_sub]) ->
Pid ! {Multi_1,Multi_2},
envia_valores_sub(Lista,Multi_2,Lista_sub).
recebe_valores_sub(Lista_sub) ->
recebe_valores_sub(Lista_sub,[]).
recebe_valores_sub([],Lista_res) ->
lists:reverse(Lista_res);
recebe_valores_sub([Pid|Lista_sub],Lista_res) ->
receive
{Pid,Res} -> ok
end,
recebe_valores_sub(Lista_sub,[Res|Lista_res]).
g_f(Parent) ->
receive
{Mult_1,Mult_2} -> ok
end,
Parent ! Mult_1*Mult_2.

2. Imagine um sistema composto por vários processos, cada
qual monitoriza um sensor. Estes sensores devem estar sempre operacionais, mas
por vezes ocorrem falhas que devem ser prontamente resolvidas, pelo que os
processos que os monitorizam devem estar constantemente operacionais. Sempre que
o sensor avaria, emite uma mensagem de erro: {‘EXIT’,Sensor_pid,Razao},
mas quando a razão é ‘fatal’,
a intervenção humana é necessária, pelo que o processo monitor deve reportar
o facto (ao seu superior) e ele próprio terminar. Nos outros casos, o monitor
deverá reinicializar o sensor, enviado-lhe uma mensagem {‘CONTROL’,reset}.
Pretende-se desenvolver um sistema tolerante a falhas que salvo a excepção
mencionada, garanta que os sensores e os monitores estão sempre activos.
a) Apresente um diagrama referente ao contexto descrito;
b) Implemente o correspondente módulo Erlang.
a)
.gif)
b)
-module(pergunta_2).
-export([master/0,monitor/2]).
master() -> process_flag(trap_exit,true), loop([]).
loop(Monitores) ->
receive
{monitor,Sensor} ->
Monitores_novo=lanca_monitor(Monitores,Sensor),
loop(Monitores_novo);
{'EXIT',Pid,fatal} ->
Monitores_novo=trata_razao_fatal(Monitores,Pid),
loop(Monitores_novo);
{'EXIT',Pid,_Razao} ->
Monitores_novo=trata_razao_outra(Monitores,Pid),
loop(Monitores_novo)
end.
monitor(Sensor,Master) ->
receive
{'EXIT',Sensor,fatal} ->
exit(fatal);
{'EXIT',Sensor,_Razao} ->
Sensor ! {'CONTROL',reset}
end,
monitor(Sensor,Master).
trata_razao_fatal(Monitores,Pid) ->
case [X || X<-Monitores,element(1,X)==Pid] of
[{Pid,Sensor}] ->
io:format("Intervenção humana necessária no sensor ~w.~n",[Sensor]),
retira_da_lista(Monitores,Pid);
_ ->
Monitores
end.
trata_razao_outra(Monitores,Pid) ->
case [X || X<-Monitores,element(1,X)==Pid] of
[{Pid,Sensor}] ->
Monitores_aux=retira_da_lista(Monitores,Pid),
lanca_monitor(Monitores_aux,Sensor);
_ ->
Monitores
end.
lanca_monitor(Monitores,Sensor) ->
Pid=spawn_link(?MODULE,monitor,[Sensor,self()]),
[{Pid,Sensor}|Monitores].
retira_da_lista(Monitores,Pid) -> [X || X<-Monitores,X=/=Pid].
3. Implemente um servidor de reservatórios de água. O servidor de estar registado com o nome servidor. O servidor deve receber as seguintes mensagens:
{PID,depositar, Nº_de_Litros} à devolve {ok,deposito,Nº_de_Litros}
{PID,levantar, Nº_de_Litros} à devolve {ok,levantamento,Nº_de_Litros_Levantados}
Quando
recebe a mensagem de depósito deve criar processos “reservatório” com uma
capacidade constante (200 L).
Um processo reservatório recebe as seguintes mensagens com o seguinte
comportamento:
{por,N_litros} à devolve {por,N_Litros_a_Mais_que_Não_cabem_no Reservatório}
{tirar,N_Litros} à devolve {tirar,N_Litros_Tirados_Efectivamente}
{ver} à devolve {ver,N_Litros_existentes}
{fim} à devolve {ok} e termina o porcesso.
Um reservatório vazio não tem razão de existir, e o seu processo deve ser terminado.
-module(pergunta_3).
-export([start/0,servidor/0,reservatorio/0]).
-define(CAPACIDADE,200).
start() -> spawn(?MODULE,servidor,[]).
servidor() -> register(servidor,self()), loop([]).
loop(Reservatorios) ->
receive
{PID,depositar,N_de_Litros} ->
Reservatorios_novo=deposita(Reservatorios,N_de_Litros),
PID ! {ok,deposito,N_de_Litros},
loop(Reservatorios_novo);
{PID,levantar,N_de_Litros} ->
{Litros_nao_levantados,Reservatorios_novo}=levanta(Reservatorios,N_de_Litros),
N_de_Litros_Levantados=N_de_Litros-Litros_nao_levantados,
PID ! {ok,levantamento,N_de_Litros_Levantados},
loop(Reservatorios_novo);
Msg ->
io:format("Msg. received: ~w.~n",[Msg]),
loop(Reservatorios)
end.
levanta([],N_de_Litros) ->
{N_de_Litros,[]};
levanta(Reservatorios,0) ->
{0,Reservatorios};
levanta([{PID,Litros}|Reservatorios],N_de_Litros) ->
case envia_levantamento(PID,N_de_Litros) of
Litros ->
termina_reservatorio(PID),
levanta(Reservatorios,N_de_Litros-Litros);
N_de_Litros ->
levanta([{PID,Litros-N_de_Litros}|Reservatorios],0);
_Else ->
exit(erro_reservatorio)
end.
envia_levantamento(PID,Litros) ->
PID ! {tirar,Litros},
receive
{tirar,Litros_retirados} ->
Litros_retirados
end.
deposita(Reservatorios,N_de_Litros) ->
case [X||X<-Reservatorios,element(2,X)<?CAPACIDADE] of
[{PID,Litros}] ->
{Resto,Reservatorios_aux}=completa_reservatorio(PID,Litros,Reservatorios,N_de_Litros);
[] ->
Resto=N_de_Litros,
Reservatorios_aux = Reservatorios
end,
cria_reservatorios(Reservatorios_aux,Resto).
completa_reservatorio(PID,Litros,Reservatorios,N_de_Litros) -> Falta=?CAPACIDADE-Litros, if Falta > N_de_Litros -> A_Depositar = N_de_Litros; true -> A_Depositar = Falta end, Resto=N_de_Litros-A_Depositar, envia_deposito(PID,A_Depositar),
Lista_completos=[X||X<-Reservatorios,element(2,X)==?CAPACIDADE],
Reservatorio_actualizado={PID,Litros+A_Depositar},
{Resto,[Reservatorio_actualizado|Lista_completos]}.
cria_reservatorios(Reservatorios,Litros) when Litros=<0 ->
Reservatorios;
cria_reservatorios(Reservatorios,Litros) when Litros=<?CAPACIDADE ->
PID=spawn(?MODULE,reservatorio,[]),
envia_deposito(PID,Litros),
[{PID,Litros}|Reservatorios];
cria_reservatorios(Reservatorios,Litros) ->
PID=spawn(?MODULE,reservatorio,[]),
envia_deposito(PID,?CAPACIDADE),
cria_reservatorios([{PID,?CAPACIDADE}|Reservatorios],Litros-?CAPACIDADE).
envia_deposito(PID,Litros) ->
PID ! {por,Litros},
receive
{por,0} ->
ok;
{por,N_Litros_a_Mais_que_Nao_cabem_no_Reservatorio} ->
io:format("Erro: reservatorio ~w deveria permitir este deposito: ~w.~n",[PID,?CAPACIDADE]),
exit(erro_reservatorio)
end.
termina_reservatorio(PID) ->
PID ! {fim},
receive
{ok} -> ok
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% RESERVATORIO
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
reservatorio() ->
loop_reservatorio(0).
loop_reservatorio(Litros) ->
receive
{por,Litros_a_depositar} ->
Litros_novo=deposita_litros(Litros,Litros_a_depositar),
loop_reservatorio(Litros_novo);
{tirar,Litros_a_retirar} ->
Litros_novo=retira_litros(Litros,Litros_a_retirar),
loop_reservatorio(Litros_novo);
{ver} ->
servidor!{ver,Litros},
loop_reservatorio(Litros);
{fim} ->
servidor ! {ok}
end.
deposita_litros(Litros,Litros_a_depositar) ->
Litros_livres=?CAPACIDADE-Litros,
if
Litros_livres>=Litros_a_depositar ->
Litros_depositados=Litros_a_depositar;
true ->
Litros_depositados=Litros_livres
end,
Litros_nao_depositados=Litros_a_depositar-Litros_depositados,
servidor ! {por,Litros_nao_depositados},
Litros_depositados+Litros.
retira_litros(Litros,Litros_a_retirar) when Litros>=Litros_a_retirar ->
servidor ! {tirar,Litros_a_retirar},
Litros-Litros_a_retirar;
retira_litros(Litros,Litros_a_retirar) when Litros<Litros_a_retirar ->
servidor ! {tirar,Litros},
0.
Última actualização: 07-12-2004