Aula nº 10

Desenvolva um módulo em Erlang que modelize uma estrutura master-slave em que o master garanta que os slaves se mantêm "vivos":

As funções a desenvolver são:

Instruções recomendadas:

Experimente esta solução que usa interface gráfica. Que diferenças nota em relação ao módulo desenvolvido? Que melhorias se poderiam incluir nesta solução e como?

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


-module(aula10).

-export([start/1, slave/0, to_slave/2]).

-define(MASTER, andy@pcigb10).

start( N ) ->
    register( master, self() ),
    process_flag(trap_exit, true ),
    Lista_slaves = cria_slaves( N, [] ),
    process_msgs( Lista_slaves ).


slave( ) ->
    receive
        die ->
            true;
        Msg ->
            io:format("Mensagem recebida: ~w~n", [Msg]),
            slave()
    end.

process_msgs( Lista_slaves ) ->
    receive
        { to_slave, Num_slave, Msg } ->
            send_msg( Lista_slaves, Num_slave, Msg ),
            process_msgs( Lista_slaves );

        { 'EXIT', Pid, Razao } ->
            case recria_slave( Lista_slaves, Pid ) of
                erro ->
                    io:format("Erro desconhecido~n", []),
                    process_msgs( Lista_slaves );

                Lista_slaves_nova ->
                    io:format("processo ~w terminou por ~w, e foi recriado~n",[element(1, hd(Lista_slaves_nova)), Razao] ),
                    process_msgs( Lista_slaves_nova )
            end
    end.

cria_slaves( 0, L ) -> L;
cria_slaves( N, L ) ->
    cria_slaves( N-1, [ { N, spawn_link(?MODULE, slave, []) } | L ] ).

recria_slave( Lista_slaves, Pid_slave ) ->
    case [X || X <- Lista_slaves, element(2, X) == Pid_slave ] of
        [ { Num_slave, Pid_slave } ] ->
            NovoSlave = { Num_slave, spawn_link(?MODULE, slave, []) },
            [ NovoSlave | [X || X <- Lista_slaves, element(2, X) =/= Pid_slave ] ];
        _ ->
            erro
    end.


send_msg( Lista_slaves, Num_slave, Msg ) ->
    case [ X || X <- Lista_slaves, element(1, X) == Num_slave ] of
        [ {Num_slave, Pid_slave} ] ->
            Pid_slave ! Msg;
        _ ->
            erro
    end.

to_slave( Msg, N ) ->
    { master, ?MASTER } ! { to_slave, N, Msg }.
Índice

Exemplo: Quit-Error-Spawn

%% Copyright (C) 1996 Ericsson Software Technology AB, Erlang Systems
%% File : qes.erl
%% Author : Anders Dahlin <anders@erlang.ericsson.se>
%% Purpose : A solution to exercise 7.2 in the Introductory Course in Erlang
%% Created : 11 Oct 1996 by Anders Dahlin <anders@erlang.ericsson.se>
%% Modified: 25 Aug 1997 by Gunilla Hugosson <gunilla@erlang.ericsson.se>

-module(qes).
-author('anders@erlang.ericsson.se').

-export([start/0,init/1]).

start() ->
	spawn(qes, init, [self()]).

init(Parent) ->
	process_flag(trap_exit, true),
	make_window(),
	loop(Parent).

loop(Parent) ->
	receive
		{gs, quitBtn, click, Data, Args} ->
			exit(normal);
		{gs, spawnBtn, click, Data, Args} ->
			spawn_link(qes, init, [self()]),
			loop(Parent);
		{gs, errorBtn, click, Data, Args} ->
			exit(error);
		{'EXIT', Parent, Reason} ->
			exit(Reason);
		{'EXIT', From, normal} ->
			loop(Parent);
		{'EXIT', From, Reason} ->
			spawn_link(qes, init, [self()]),
			loop(Parent)
	end.

%% ----------------------------------------------------------------------
%% Opens a window with three buttons for
%% QUIT: Closes window and all child windows
%% SPAWN: Spawns of a child window
%% ERROR: Dies because of an error, all children will also die.
%% The window should be restarted by the parent window.
%% Title of the window will be the pid of the calling process.
%% The calling process will receive messages when a button is pressed.
%% Messages look like:
%% {gs, ButtonName, click, _Data, _Args}
%% where ButtonName is: quitBtn, spawnBtn or errorBtn
%% Returns: ok
%% ----------------------------------------------------------------------
make_window() ->
	W = gs:create(window, gs:start(), [{width,150}, {height,30}]),
	Q = gs:create(button, quitBtn, W, [{bg, green}, {width,50}, {x,0}, {y,0},
		{label, {text, "Quit"}}]),
	S = gs:create(button, spawnBtn, W, [{bg, lightblue}, {width,50}, {x,50},
		{y,0}, {label, {text, "Spawn"}}]),
	E = gs:create(button, errorBtn, W, [{bg, red}, {width,50}, {x,100}, {y,0},
		{label, {text, "Error"}}]),
	gs:config(W, [{title, pid_to_list(self())}, {map, true}]), ok.
Índice

Última actualização: 18 Abr 2005

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