Ligações entre processos

O Erlang permite que determinados processos monitorizem o comportamento doutros processos no sistema. Este mecanismo assenta em duas características principais:

As ligações entre processos podem ser estabelecidas no momento da criação do novo processo ou tempo de execução. Sempre que um processo termina (normalmente ou não) envia um sinal de EXIT a todos os processos com os quais possui uma ligação. Este sinal tem o seguinte formato:

{'EXIT', PID, Razão}

PID é o identificador do processo que termina. Razão é um termo Erlang, indicando qual a razão do processo ter terminado.

Na recepção dum sinal EXIT em que a razão não seja o átomo normal , a acção por omissão do processo receptor é terminar e enviar um sinal EXIT para todos os processos aos quais esteja actualmente ligado, tal como se pode ver na figura seguinte:

Propogação de um sinal EXIT

Fig 1 - Propagação de um sinal EXIT

Este comportamento por omissão pode ser alterado de modo a permitir que um processo tome as acções necessárias na recepção dum sinal EXIT. Este assunto será abordado na próxima aula. 

Quando um processo termina normalmente envia o sinal {'EXIT',self(), normal} para todos os processos aos quais está ligado. Neste caso o processo receptor ignora o sinal e não o propaga. 

Para terminar a execução do processo pode ser usada a BIF exit(Razão). Razão é um termo Erlang, que pode ser apanhado com a primitiva catch.

Criação e remoção de ligações entre processos

Todas as ligações entre processos são bidireccionais, isto é, se um processo A estabelece uma ligação a um processo B então o processo B é automaticamente ligado ao processo A.

Uma ligação entre dois processos é estabelecida usando a BIF link(Pid).

Executar a função link(Pid) quando já existe uma ligação entre os dois processos não tem qualquer efeito. Todas as ligações que um processo detenha são removidas quando o processo termina.

Um processo pode explicitamente remover uma ligação chamando a função unlink(Pid).

Executar a função unlink(Pid) quando já não existe qualquer ligação entre os dois processos não tem qualquer efeito.

O Erlang possui ainda a função spawn_link/3 que, para além de criar um novo processo, estabelece automaticamente uma ligação com esse processo. Esta função, à semelhança de spawn/3 retorna o Pid do novo processo.


Exercícios

1) Lance 4 processos que aguardam mensagens. Cada um destes processos deve estabelecer um link com o seu sucessor.

Sempre que enviar uma mensagem ao primeiro processo, este imprime-a e envia-a ao segundo processo. O segundo e terceiro processo repetem o procedimento enviando a mensagem ao seu sucessor. O quarto apenas imprime a mensagem recebida. No entanto, se receber a mensagem stop deve terminar com a razão terminei (usando exit(terminei)).

Deve verificar que o sinal de EXIT se propaga a todos os processos, enviando uma nova mensagem ao primeiro processo. Analise o resultado.

Para tornar o exercício mais interessante apenas deve registar o primeiro processo com um dado nome. A comunicação com os restantes processos deve ser efectuada usando Pids.

2) Crie um processo que represente um servidor de recursos (impressora, disco, memória, cpu, etc.). Sempre que este processo recebe um pedido de um qualquer cliente para alocar um determinado recurso:

Quando o cliente deixa de usar o recurso envia a mensagem {liberta_recurso, Recurso} ao servidor. O servidor deve verificar se o processo que pretende libertar o recurso é o processo que o detém. Se esta condição se verificar o recurso passa a ficar disponível para os restantes processos.

Sempre que é atribuído um recurso a um cliente deve ser estabelecido um link com esse processo. Do mesmo modo, quando o cliente liberta o recurso, o link deve ser removido.

Pode completar o exercício com uma lista de espera (FIFO ou com prioridades para os clientes) para cada um dos recursos disponíveis.