Aula nº 6

Baseado no exercício da aula anterior, altere-o de forma que:

  1. Cada processo vote apenas uma vez;
  2. As mensagens transaccionadas entre o top e o votante/consultor se referem a uma única e mesma conversão.

Funções e librarias a usar:

OC 98-99 (Exercícios Práticos)


% as alterações para responder ao ponto 1 sao apresentadas a verde
% as alterações para responder ao ponto 2 sao apresentadas a vermelho
% define uma constante denominada FILENAME com o valor aula6
-define(FILENAME, aula6).
% especifica o nome do módulo como sendo aula6
-module(?FILENAME).
-export([start/1, top/0, consultar/1, consultar/2, votar/2]).
start(No) -> spawn(No, ?FILENAME, top, []).
top() ->
    register(top, self()),
    Bandas = dict:new(),
    Votantes = dict:new(),
    top_processo(Bandas, Votantes).
top_processo(Bandas, Votantes) ->
    receive
        { consultar, Ref, Requisitante } ->
            Requisitante ! { consultar_resposta, Ref, Bandas },
            top_processo(Bandas, Votantes);
        { consultar, Ref, Requerente, Banda } ->
            case dict:find(Banda, Bandas) of
                error -> Val = 0;
                {ok, V} -> Val = V
            end,
            Requerente ! { consultar_resposta, Ref, {Banda, Val} },
            top_processo(Bandas, Votantes);
        { votar, Ref, Votante, Banda } ->
            % verifica se este PID ja votou
            case dict:find(Votante, Votantes) of
                error ->
                    % se ainda nao votou, pode votar
                    case dict:find(Banda, Bandas) of
                        error -> Val = 1;
                        {ok, V} -> Val = V + 1
                    end,
                    BandasNovo = dict:store(Banda, Val, Bandas),
                    VotantesNovo = dict:store(Votante, [], Votantes),
                    Votante ! {votar_resposta, Ref, {Banda, Val} },
                    top_processo(BandasNovo, VotantesNovo);
                {ok, _} ->
                    % se ja votou, nao pode votar mais
                    Votante ! {votar_resposta, Ref, ja_votou },
                    top_processo(Bandas, Votantes)
            end
    end.
% por cada mensagem de consulta e gerada uma referencia
% que sera posteriormente devolvida por top/0 para autenticar
% a mensagem recebida.
consultar(Top) ->
    Ref = make_ref(),
    Top ! {consultar, Ref, self() },
    receive
        { consultar_resposta, Ref, Resultado } -> Resultado
    end.
consultar(Top, Banda) ->
    Ref = make_ref(),
    Top ! { consultar, Ref, self(), Banda},
    receive
        { consultar_resposta, Ref, Resultado } -> Resultado
    end.
% por cada mensagem enviada, gera uma referencia que guarda numa lista.
% essa lista vai sendo criada a cada chamada de emite_votos/3.
% a lista e retornada para votar/2 e sera usada em recebe_respostas/2
% para confirmar a autenticidade da mensagem recebida.
votar(Top, ListaBandas) ->
    %% ponto 1
    Refs = emite_votos(Top, ListaBandas, []),
    recebe_respostas(ListaBandas, Refs).
emite_votos(_, [], Refs ) ->
    io:fwrite("todos os votos foram emitidos~n"),
    Refs;
emite_votos(Top, [H|ListaBandas], Refs ) ->
    Refs = make_ref(),
    Top ! { votar, Ref, self(), H },
    emite_votos( Top, ListaBandas, [Ref|Refs] ).
recebe_respostas([], []) -> true;
recebe_respostas( [H|ListaBandas], [Ref|Refs] ) ->
    recebe_respostas( ListaBandas, Refs ),
    receive
        { votar_resposta, Ref, Resultado } -> io:fwrite("~s~n", [io_lib:write(Resultado)]);
        { votar_resposta, Ref, ja_votou } -> io:fwrite("ja votou.")
    end.
Índice

Última actualização: 14 Março 2000

OC 98-99 (Exercícios Práticos)