Buscar

lista 3 2012 1

Prévia do material em texto

3ª Lista de Exercícios de Paradigmas de Linguagens Computacionais
Professores: Fernando Castor e Márcio Cornélio
Monitores:
Ciência da computação: Alberto Costa Jr. (arcj), David Hulak (dbh), Glauco dos 
Santos (grps), Jessica Barbalho (jcb), Renato Oliveira (rso), Luís Gabriel Lima (lgnfl), 
Vanessa Gomes (vgl), Walter Lima Filho (wflf)
Engenharia da Computação: Alan Gomes (aga), Álvaro Silvino (ajsss), Felipe 
Araújo (fsa2), Gabriel Avelar (gafm), Larissa Paz (lorp), Lívia Vilaça (lcjbv), Lucas 
Inojosa (licf), Pedro Araujo (pam2).
CIn-UFPE – 2012.1
Disponível desde: 10/05/2012
Entrega: 31/05/2012
A lista deverá ser respondida em dupla. A falha em entregar a lista até a data 
estipulada implicará na perda de 0,25 ponto na média da disciplina para os membros 
da dupla. Considera-se que uma lista na qual menos que 4 das respostas estão 
corretas não foi entregue. A entrega da lista com pelo menos 7 das questões 
corretamente respondidas implica em um acréscimo de 0,125 ponto na média da 
disciplina para os membros da dupla. A questão 5 é obrigatória e não respondê-la é 
equivalente a não entregar nenhuma resposta. Se qualquer situação de cópia 
de respostas for identificada, os membros de todas as duplas envolvidas 
perderão 0,5 ponto na média da disciplina. O mesmo vale para respostas obtidas a 
partir da Internet. As respostas deverão ser entregues exclusivamente em 
formato texto ASCII (nada de .pdf, .doc, .docx ou .odt) e deverão ser enviadas para 
o monitor responsável por sua dupla, sem cópia para o professor. Devem ser 
organizadas em arquivos separados, um por questão, entregues em um único formato 
compactado, ou seja, um único arquivo zipado contendo as respostas para todas as 
questões. 
1) Está acontecendo uma competição de programação (para programadores extrema-
mente rápidos e que nunca erram), em que N (>=2) times devem resolver uma quanti-
dade Y (>0) de questões. Considere as seguintes informações:
- Cada time é composto por três membros.
- Só é fornecido um computador para cada time (logo os membros terão que se re-
vezar no computador).
- A resolução de uma questão é feita individualmente por cada membro do time em 
duas etapas: Leitura/entendimento e Programação 
- Cada membro do time lê/entende uma questão no tempo entre 1000ms e 1500ms 
e depois vai programa-la caso o computador esteja livre, caso contrário espera até 
que o computador esteja livre.
- Cada membro do time quando estiver ocupando o computador, programa a ques-
tão que foi lida/entendida no tempo entre 500ms e 2000ms, ao final ele vai ler outra 
questão liberando o computador para outro membro do time.
– Assim que um time resolver as Y questões a competição será interrompida. Im-
prima o ranking dos times em ordem decrescente do número de questões que cada 
um resolveu.
–
2) P pessoas querem se inscrever em um curso de uma instituição. Há B balcões com 
B atendentes para inscrever essas P pessoas. A cada balcão é designada uma fila de 
pessoas com no máximo 10 pessoas por fila. Cada pessoa tem uma identificação (um 
número natural chamado de ID). Quando uma pessoa chega para se inscrever em um 
curso, ela precisa entrar em uma fila de um balcão. O número do balcão escolhido para 
uma determinada pessoa é ID%B. 
 Cada pessoa só pode ser inscrita uma vez (logo, só pode entrar em uma fila de 
um balcão uma vez). A ordem em que cada pessoa chega à instituição deve ser 
aleatória (sugestão: utilize Collection.shuffle() para criar uma lista de pessoas 
desordenada). Se uma pessoa entra na instituição e a fila na qual deve entrar está 
cheia, esta pessoa deve esperar que um espaço seja liberado na fila. Se um atendente 
não tem ninguém para atender, ele vai dormir por 1 milissegundo.
Cada balcão atende pessoas concorrentemente. Considere que a instituição 
possui 5 entradas e que as pessoas entram aleatoriamente (utilize Math.random()) por 
elas e de modo concorrente. Cada pessoa entra por uma determinada entrada a cada 1 
segundo. Se a fila desse balcão estiver cheia quando a pessoa tentar entrar, ela espera 
pacientemente até que uma vaga seja aberta na fila e a entrada fica bloqueada por esta 
pessoa esperando. O seu programa deve terminar quando todas as pessoas forem 
inscritas no curso ou quando o programa rodar por T segundos. 
Coloque T, P e B como constantes estáticas na mesma classe que contém a 
função main. As pessoas escolhidas serão armazenadas em uma 
LinkedBlockingQueue, cada fila deve ser uma ArrayBlockingQueue de capacidade 10 e 
cada balcão deve ser armazenado em um ConcurrentHashMap de tamanho B. Ou seja, 
cada chave do map é ID%B e cada valor é o balcão correspondente (cada balcão 
contendo seu ArrayBlockingQueue).
Seu programa deve realizar as seguintes impressões (seguidas de uma quebra 
de linha) em um arquivo de texto, quando o evento em questão ocorrer:
- “A pessoa i entrou pela porta p”, em que p é o número da porta (de 0 a 4) e i é o ID 
da pessoa (de 0 a P-1).
- Quando um atendente terminar de atender uma pessoa (ou seja, colocou-a na fila), 
deve ser impresso “O atendente b terminou de atender a pessoa p”, em que b é o 
número do balcão (de 0 até B-1).
- “A pessoa p entrou na fila do balcão b”.
- Ao término do programa devem ser impressos os ID’s das pessoas escolhidas, na 
ordem em que forem escolhidas, separados por um espaço em branco.
3)O programa abaixo representa uma cafeteria onde existem N banheiros e C 
consumidores. Esses consumidores bebem café e usam o banheiro. Para usar o 
banheiro o consumidor precisa pegar a chave do banheiro, e assim que terminar de 
usar o banheiro o consumidor coloca a chave no quadro de chaves dos banheiros. 
Logo, o consumidor só pode usar um banheiro se houver chaves disponíveis no 
quadro.
Nesta questão você deverá modificar o programa abaixo para que deixe de utilizar 
escopos sincronizados e passe a utilizar exclusivamente tipos de dados atômicos 
(aqueles que existem no pacote java.util.concurrent.atomic). O programa 
resultante de suas modificações deve se comportar exatamente da mesma forma que o 
programa abaixo e nunca deve entrar em deadlock ou apresentar condições de corrida.
import java.util.Scanner;
class Consumidor extends Thread{
int loop;
int passo = 1;
int nome;
boolean continua = true;
public Consumidor(int qtdLoop, int n){
this.loop = qtdLoop;
this.nome = n;
}
@Override
public void run() {
System.out.println("Consumidor"+this.nome+"entrou!");
while(this.continua){
/**
 * Consumidor entra na cafeteria e por K vezes
 * 
 * Bebe café
 * Pega uma chave
 * Usa o banheiro
 * Devolve a chave
 * 
 * Sai da cafeteria
 * 
 * */
//Bebe café
if(this.passo == 1){
System.out.println("Consumidor"+this.nome+"está bebendo café!");
int tempo = (int)((Math.random()*3000) + 8000);
try {
sleep(tempo);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.passo = 2;
}
// Pega chave
if(this.passo == 2){
if(Cafeteria.decrementaQuadro()){
this.passo = 3;
}
}
//Usa o banheiro
if(this.passo == 3){
System.out.println("Consumidor"+this.nome+"está usando o banheiro!");
int tempo = (int)((Math.random()*3000) + 8000);
try {
sleep(tempo);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.passo = 4;
}
//Devolve a chave
if(this.passo == 4){
if(Cafeteria.incrementaQuadro()){
this.loop--;
this.passo = 1;
}
}
if(this.loop == 0){
this.continua = false;
}
}
System.out.println("Consumidor " + this.nome + " saiu da cafeteria!");
}
}
public class Cafeteria {
static int quadro;
static int chave;
public Cafeteria(int n, int consumidores, int loop) {
quadro = n;
chave = n;
for (int i = 1; i <= consumidores; i++) {
Consumidorconsu = new Consumidor(loop, i);
consu.start();
}
}
public static synchronized boolean incrementaQuadro(){
if(quadro < chave){
quadro++;
return true;
}else{
return false;
}
}
public static synchronized boolean decrementaQuadro(){
if (quadro > 0){
quadro--;
return true;
}else{
return false;
}
}
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
System.out.println("Quantos banheiros existem na Cafeteria? ");
int banheiros = console.nextInt();
System.out.println("Quantos consumidores estão na cafeteria? ");
int consumidores = console.nextInt();
System.out.println("Quantes idas ao banheiro? ");
int k = console.nextInt();
Cafeteria cafe = new Cafeteria(banheiros, consumidores, k);
}
}
4) Imagine que exista um mapa, representado por um array bidimensional de inteiros, 
onde duas formigas possam andar sobre ele. A cada instante, cada formiga escolhe 
aleatoriamente uma posição ao seu redor para se mover, mas, se a posição escolhida já 
estiver ocupada por outra formiga, aguarda até que esse espaço seja liberado. Leia o 
código java abaixo, identifique o que está causando o deadlock e encontre uma solução 
simples para resolver o problema que não resulte em outros problemas, como 
condições de corrida e starvation.
public class Ant {
private int[][] mapa;
public Ant(){
//Bidimensional map
mapa = new int[3][3];
Formiga f1 = new Formiga("Philip Fry", mapa, 0, 0);
mapa[0][0] = 1;
Formiga f2 = new Formiga("Bender Rodriguez", mapa, 1, 1); 
mapa[1][1] = 1;
f1.start(); f2.start();
}
public static void main(String[] args){
new Ant();
}
}
class Formiga extends Thread {
private int[][] mapa;
private int posicaoX;
private int posicaoY;
private String nome;
public Formiga(String nome, int[][] mapa, int posicaoX, int posi-
caoY){
this.nome = nome;
this.mapa = mapa;
this.posicaoX = posicaoX;
this.posicaoY = posicaoY;
}
private void printMap(){
for (int i = 0; i < mapa.length; i++){
for (int j = 0; j < mapa[i].length; j++){
System.out.print(mapa[i][j] + " ");
}
System.out.println();
}
}
public void run(){
while (true){
andar();
}
}
public synchronized void andar(){
int novoX = posicaoX;
int novoY = posicaoY;
//Choosing new place to go
while (novoX == posicaoX && novoY == posicaoY){
//Randomizing new position
novoX = (int) ((posicaoX - 1) + (Math.round(Math.ran-
dom()*2)));
novoY = (int) ((posicaoY - 1) + (Math.round(Math.ran-
dom()*2)));
//Keeping new position inside array bounds
if (novoX < 0) novoX = 0;
if (novoY < 0) novoY = 0;
if (novoX >= mapa.length) novoX = mapa.length - 1;
if (novoY >= mapa[novoX].length) novoY = 
mapa[novoX].length - 1;
}
System.out.println("[" + nome + "] Anterior: (" + posicaoX 
+ "," + posicaoY + "); Nova posição: (" + novoX + "," + novoY + ")");
while (mapa[novoX][novoY] == 1){
//Wait before new position is free
}
//Performing movement
mapa[posicaoX][posicaoY] = 0;
mapa[novoX][novoY] = 1;
posicaoX = novoX;
posicaoY = novoY;
System.out.println(nome + " andou");printMap();
//Rest a little
try {
sleep((long) (25 + Math.random() * 50));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
5) Considere que uma galinha pode ser modelada por 4 Threads. Cada thread 
representa a função de uma parte do corpo.
Os olhos procuram por comida e informam ao cérebro sempre que alguma 
comida for detectada. Uma vez que a comida é localizada, o cérebro avisa aos pés para 
se moverem certa distância com o objetivo de alcançar a comida. Uma vez que os pés 
tiverem movido a distância indicada, eles informam ao cérebro, e esse, por sua vez, 
avisa a boca para começar a comer.
Essas galinhas não tem memória, a qualquer momento os olhos podem 
identificar outra comida. Isso vai acarretar em: o cérebro avisar aos pés para parar 
qualquer caminhada e a boca parar de comer, os pés começarem a se mover em 
direção a nova comida, e em seguida comê-la.
Escreva um programa que simula o comportamento dessa galinha. As threads 
devem se comportar como descrito abaixo:
- Olhos: procuram por comida a cada tempo t ms (t está entre 1000 e 2000), 
achando comida 50% das vezes. Cada vez que os olhos buscam por comida a string 
"procurando..." é impressa.
- Cérebro: recebe sinal dos olhos indicando que foi encontrado comida. Uma vez 
informado, a string "comida!" é impressa e em seguida informa a boca para parar de 
comer, aos pés para pararem qualquer movimentação e se moverem em direção à nova 
comida encontrada. Uma vez que os pés indicam que o destino foi alcançado a string 
"yes!" é impressa e a boca é avisada para começar a comilança.
- Pés: recebem sinal do cérebro indicando nova comida. Uma vez avisados, 
param qualquer movimento que esteja sendo feito, e movem-se um número randômico 
de passos (entre 5 e 10) en direção à nova comida. São gastos 400ms por passo. 
Depois de cada passo deve-se imprimir a string "passo". Uma vez que uma sequência 
de passos tenha sido finalizada, o cérebro deve ser avisado que o destino já foi 
alcançado.
- Boca: aguarda por um sinal do cérebro para começar a comer. Fica comendo 
até que seja informada para parar. Cada bocanhada leva 400ms e para cada uma deve 
ser impresso uma string "comendo".
A simulação só deve terminar quando o usuário matar o processo. Sua 
implementação não pode empregar travamento explícito ou monitores (nada de locks, 
synchronized, wait, notify, signal, await, etc.).
6) Considere a Classe ProdutorConsumidor abaixo:
import java.util.Stack;
public class ProdutorConsumidor {
public static Stack<Integer> buffer = new Stack<Integer>();
public static void main(String[] args) {
Runnable produtor = new Runnable() {
public void run() {
for(int i = 0; i < 100000; i++){
buffer.push(i);
}
}
};
Runnable cons = new Runnable() {
public void run() {
for(int i = 0; i < 100000; i++){
System.out.println(buffer.pop());
}
}
};
new Thread(produtor).start();
new Thread(cons).start();
}
}
Edite a classe ProdutorConsumidor para que, utilizando apenas o conceito de monitores 
e comunicação entre threads, ela funcione como funcionaria se fosse sequencial, exce-
to pela ordem em que as operaçõs push() e pop() são chamadas, em todas as situa-
ções. (não utilize locks explícitas, nem o método sleep()). Considere que a pilha pode 
ter no máximo 200 itens e certifique-se de que não é possível incluir itens nela quando 
ela já alcançou esse limite nem remover itens quando está vazia.
7) Barracas de tiro ao alvo são muito comuns em festividades juninas. Uma barraca 
possui 4 caixas que vendem os tiros. Existem pacotes de compras diferentes (De 3 tiros 
por vez até 20 tiros por vez - pacotes de tiros), e por isso, cada vez que o cliente com-
pra "a vez", ele pode pagar preços diferentes. A barraca tem estrutura pra funcionar 
para pelo menos 400 clientes, e a quantidade de clientes, o nome, o preço de cada pa-
cote de tiros devem ser definidos num arquivo à parte - na definição do arquivo, gere a 
quantidade de tiros de cada cliente aleatoriamente. Um cliente pode querer dar mais ti-
ros do que estão disponíveis no pacote máximo de 20 tiros. Neste caso, ele compra ti-
ros, espera um tempo (durante o qual ele está dando os tiros) e depois volta para a bar-
raca. O preço dos tiros é único. (Você pode muito bem nomear os clientes como C1, C2, 
C3, etc.)
Modele cada cliente e cada barraca como uma thread diferente. Além disso, vo-
cênão precisa modelar explicitamente o momento em que o cliente vai atirar (a thread 
apenas espera por um período de 1s), apenas aquele em que ele compra os tiros. 
Como dito, considere que existem de 3 a 20 tipos de pacotes de tiro diferentes e que a 
escolha do pacote que será vendido é feita aleatoriamente. Os clientescompram paco-
tes de tiros em intervalos aleatórios. Imprima na tela, para cada cliente, o nome, a quan-
tidade de tiros comprada e o total gasto. Considere que por noite de trabalho, a barraca 
vende pelo menos 10000 tiros.
8) Crie um semáforo de trânsito um pouco mais inteligente que os semáforos 
existentes atualmente. Imagine um cruzamento onde há um semáforo de dois tempos, 
um tempo controla se os carros da vertical devem seguir ou parar e o outro tempo 
controla se os carros da horizontal devem seguir ou parar. Os carros não podem dobrar, 
eles só podem seguir em frente no cruzamento. Cada tempo deve ficar aberto durante 
um intervalo X de segundos que deverá ser determinado pelo usuário. Contudo há duas 
situações onde esse intervalo pode ser desrespeitado: se em X/4 segundos nenhum 
carro passar no cruzamento, em nenhum dos sentidos, o sinal fecha e seu oposto abre; 
se alguma fila da direção oposta atingir um número Y de carros, definido pelo usuário, o 
tempo para esta direção é aberto (consequentemente seu oposto é fechado).
Considere que cada carro leva 2 segundos para cruzar o semáforo, uma vez que 
ele esteja na primeira posição, se ele estiver na segunda posição ele leva o tempo do 
primeiro carro, mas o tempo dele mesmo, ou seja 4 segundos e por aí vai.
Em cada uma das 4 filas os carros aparecem em intervalos randômicos que podem vari-
ar de X/50 segundos a X/10 segundos e cada fila é independente da outra. O carro que 
aparecer ocupa a próxima posição disponível da fila.
Ambos os tempos nunca devem ficar abertos no mesmo momento, nem fecha-
dos no mesmo momento. Evite acidentes, mas não cause engarrafamento.
Obs: Sentido e direção são coisas diferentes. Neste caso direção é horizontal ou verti-
cal, cada uma com dois sentidos.
9) A cidade de GrayVille está em guerra! Devido aos recentes avanços da tecnologia 
local os ferreiros da cidade desenvolveram um tipo de canhão que é carregado com 3 
munições. Cada tiro demora 500ms e cada canhão demora 3 segundos para ser 
recarregado. Porém, devido a guerra, só existe na cidade uma pessoa capaz de 
recarregar os canhões. Considere que a cidade possui 5 canhões e quando um está 
sendo carregado e outro fica sem munição, ele entra em uma fila para aguardar sua 
vez. Considere também que existe uma quantidade finita de munição na cidade, quando 
acabar a munição imprima quantas balas cada canhão atirou.
Implemente o problema da cidade de GrayVille com locks explícitos e 
travamento não-bloqueante e considere cada canhão como uma thread.

Continue navegando