Laboratório 11 - 30/5/2001
Na aula passada discutimos um padrão de observador, muito
comum em programas orientados a objetos, onde um observador
registra seu interesse em determinado evento através de uma
função de callback a ser chamada quando esse
evento ocorrer.
Em C podemos simular esse comportamento, apesar de não termos
o conceito de objetos, registrando endereços de funções que
devem ser chamadas quando o evento ocorrer. Como essas funções
não correspondem a objetos específicos, é comum que precisemos
registrar alguma outra informação que caracterize o
interessado no evento.
Como exemplo, considere a situação onde o sujeito
é um thread responsável por gerenciar um valor inteiro e
os observadores são threads interessadas em alterações
desse valor.
O programa exemplo mostra um programa
bem simples que modela essa situação.
Nesse programa, todos os observadores seguidamente se bloqueiam
a espera de alterações no valor observado, e a função de
callback recebe como parâmetro a condição específica
de cada observador (essa é a informação que caracteriza cada
observador).
-
Acompanhe a execução desse programa e entenda como ele
funciona.
Repare que com a estrutura apresentada, um observador
poderia "perder" valores, isto é, poderia não conseguir
imprimir todos os valores de
valorobservado
.
-
Modifique seu programa do broadcast atômico para que
ele passe a utilizar uma estrutura de callback.
Agora, quando um consumidor não encontrar um item novo,
ele não deve mais se bloquear dentro do monitor,
e sim registrar uma função de callback e uma informação
adicional para ser avisado quando aparecer um novo item.
(Associe a cada posição do buffer um array onde cada
posição contém um endereço de função e um ponteiro
void *
)
Ao voltar da retira
, o consumidor
deve verificar se teve sucesso, e, em caso negativo,
deve se bloquear.
Pense nas condições de corrida e sequências de bloqueios
que podem acontecer agora...
-
Modifique o programa para incluir
dois tipos de threads consumidores.
O primeiro tipo de consumidor é o anterior.
Um novo tipo de consumidor deve registrar uma função
de callback que altera uma variável do consumidor.
Esse consumidor novo não se bloqueia enquanto
espera as alterações: ele fica em um loop, simulando
que está fazendo alguma atividade (por exemplo, periodicamente
escrevendo um caracter na tela), e de tempos em tempos
verifica se a variável foi alterada ou não.
Nesse caso você vai trabalhar com diferentes
funções de callback.
A informação específica de cada thread consumidor
não vai mais ser uma condição no segundo caso.