Exercício 12

OC 1999/2000 (Exercícios Práticos)


Enunciado

Altere o exercício 7, por forma a tornar o sistema tolerante a falhas.

Escolha a melhor estratégia de controlo em função do sistema e da implementação já existente.


Solução

-module(exercicio12).
-export([start/2,init/2,coluna/1,elemento/1]).

start(A,B) ->
	spawn(?MODULE,init,[A,B]).

init(A,B) ->
	process_flag(trap_exit,true),
	Pids=criar_nodes(coluna,length(B)),
	Pids_Cols=envia_dados(Pids,A,B),
	Resultado=recebe_resultados(Pids_Cols,coluna,A,B),
	io:format("Resultado: ~w.~n",[Resultado]).

criar_nodes(Funcao,N) ->
	criar_nodes(Funcao,N,[]).

criar_nodes(Funcao,0,Pids) -> Pids;
criar_nodes(Funcao,N,Pids) ->
	P=spawn_link(?MODULE,Funcao,[self()]),
	criar_nodes(Funcao,N-1,[P|Pids]).

envia_dados(Pids,A,B) ->
	envia_dados(Pids,A,B,[],1).

envia_dados([],_,_,Pids_Cols,_) -> Pids_Cols;
envia_dados([P|Pids],A,[Coluna|B],Pids_Cols,N) ->
% para dar erro... (apenas da primeira vez)
	P ! 2, % {A,Coluna},
	envia_dados(Pids,A,B,[{N,P}|Pids_Cols],N+1).

reenvia_dados(N,[{N,Pid}|Pids],A,[Coluna|B]) ->
	Pid!{A,Coluna};
reenvia_dados(N,[Pid|Pids],A,[Coluna|B]) ->
	reenvia_dados(N,Pids,A,B).

recebe_resultados(Pids_Cols,Funcao,A,B) ->
	recebe_resultados(Pids_Cols,[],Funcao,A,B,length(B)).
recebe_resultados(_Pids_Cols,Resultados,_Funcao,_A,_B,0) -> Resultados;
recebe_resultados(Pids_Cols,Resultados,Funcao,A,B,N) ->
	P=get_nth_pid(Pids_Cols,N),
	receive
		{'EXIT',_,normal} ->
			recebe_resultados(Pids_Cols,Resultados,Funcao,A,B,N);
		{'EXIT',Pid_dead,Reason} ->
			io:format("Recriado ~w.~n",[Funcao]),
			{M,Pids_Cols_new}=recria_node(Pid_dead,Funcao,Pids_Cols),
			reenvia_dados(M,Pids_Cols_new,A,B),
			recebe_resultados(Pids_Cols_new,Resultados,Funcao,A,B,N);
		{P,Resultado} ->
			recebe_resultados(Pids_Cols,[Resultado|Resultados],Funcao,A,B,N-1)
	end.

get_nth_pid([],_) -> exit(inconsistency_error);
get_nth_pid([{N,P}|Pids_Cols],N) -> P;
get_nth_pid([{_N,_P}|Pids_Cols],N) -> get_nth_pid(Pids_Cols,N).

coluna(Pid_start) ->
	process_flag(trap_exit,true),
	receive
		{A,Coluna} -> ok;

		% necessario para que de erro
		A -> Coluna=A, exit(error)
	end,
	Pids=criar_nodes(elemento,length(Coluna)),
	Pids_elem=envia_dados(Pids,Coluna,A),
	Resultados=recebe_resultados(Pids_elem,elemento,Coluna,A),
	Pid_start ! {self(),Resultados}.

elemento(Pid_coluna) ->
	receive
		{Linha,Coluna} -> ok;

		% necessario para que de erro
		Linha -> Coluna=Linha, exit(error)
	end,
	Elem=multiplica_linha_coluna(Linha,Coluna),
	Pid_coluna ! {self(),Elem}.

multiplica_linha_coluna(L,C) ->
	multiplica_linha_coluna(L,C,0).

multiplica_linha_coluna([],[],Elem) -> Elem;
multiplica_linha_coluna([L1|L],[C1|C],Elem) ->
	multiplica_linha_coluna(L,C,Elem+C1*L1).

recria_node(Pid_dead,Funcao,Pids_Cols) ->
	recria_node(Pid_dead,Funcao,Pids_Cols,[]).
recria_node(Pid_dead,Funcao,[],Pids_Cols_new) -> Pids_Cols_new;
recria_node(Pid_dead,Funcao,[{N,Pid_dead}|Pids_Cols],Pids_Cols_new) ->
	Pid_new=spawn_link(?MODULE,Funcao,[self()]),
	Pids_Cols_rest=lists:append(Pids_Cols,Pids_Cols_new),
	{N,[{N,Pid_new}|Pids_Cols_rest]};
recria_node(Pid_dead,Funcao,[{N,P}|Pids_Cols],Pids_Cols_new) ->
	recria_node(Pid_dead,Funcao,Pids_Cols,[{N,P}|Pids_Cols_new]).


Última actualização: 23-05-2000

OC 1999/2000 (Exercícios Práticos)