Desafio do Papai Noel (Santa Claus problem)

0 respostas
threadsjavaprogramação
S

Olá meus caros amigos. Estou com um desafio muito interessante dado pelo meu professor em uma cadeira de processamento paralelo na faculdade. Segundo ele, é um problema bastante conhecido no meio da computação quando se fala no uso de threads e multiprocessamento. O enunciado é o seguinte:

“O problema é
basicamente composto por dez elfos, nove renas e pelo Papai Noel. A vida do Papai
Noel se resume a dormir até que ele seja acordado pelas nove renas ou por um grupo
de três elfos. Caso seja acordado pelas renas, o Papai Noel as amarra ao trenó, distribui
brinquedos, desamarra-as e volta a dormir. Caso seja acordado pelos elfos, o Papai
Noel discute projetos de brinquedos e volta a dormir. A vida de uma rena se resume a
entregar presentes e tirar férias até o próximo ano. A vida de um elfo se resume a
fabricar brinquedos e se reunir com o Papai Noel. Papai Noel dorme em sua casa no
Polo Norte, e só pode ser despertado por 9 renas (todas), quando estão voltando de
suas férias de alguma ilha tropical, ou por alguns elfos, que estão tendo dificuldades em
fazer os brinquedos. O problema de um elfo nunca é grave o suficiente para acordar o
Papai Noel (caso contrário, ele pode nunca conseguir dormir), então, os elfos visitam o
Papai Noel em um grupo de três. Quando os três elfos tem seus problemas resolvidos,
qualquer outro elfo que deseje visitar o Papai Noel deve esperar que os elfos retornem.
Se o Papai Noel acordar e encontrar três elfos esperando na porta de sua loja, junto
com a última rena voltando dos trópicos, o Papai Noel decide que os elfos podem
esperar até depois do Natal, porque é mais importante preparar seu trenó assim que
que possível. Supõe-se que as renas não querem deixar as férias, portanto, ficam lá até
o último momento possível.”

Segue o código de uma solução que alcancei:

import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Semaphore;

public class PapaiNoel {

    private static Random numeroAleatorio = new Random();

    private final Semaphore atencaoDoPapaiNoel;
    private final Semaphore filaDeElfos;
    private final CyclicBarrier tresElfos;
    private final CyclicBarrier noveRenas;
    private final CyclicBarrier treno;
    private final CyclicBarrier problemaResolvido;

    private final static int numeroDeRenas = 9;
    private final static int numeroDeElfos = 10;
    private final static int elfosParaAcordar = 3;
    private final static int ultimaRena = 0;
    private final static int terceiroElfo = 0;

    private PapaiNoel () {
        atencaoDoPapaiNoel = new Semaphore(1, true);
        filaDeElfos = new Semaphore(elfosParaAcordar, true);
        tresElfos = new CyclicBarrier(elfosParaAcordar, new Mensagem("> " + elfosParaAcordar + " elfos precisam de ajuda!"));
        noveRenas = new CyclicBarrier(numeroDeRenas, () -> System.out.println(">>> Todas as renas em casa para a entrega!!"));
        treno = new CyclicBarrier(numeroDeRenas, new Amarracao());
        problemaResolvido = new CyclicBarrier(elfosParaAcordar, new Mensagem("> Elfos de volta ao trabalho..."));

        ArrayList<Thread> threads = new ArrayList<>();

        for (int i = 0; i < numeroDeElfos; i++) {
            threads.add(new Thread(new Elfo(i)));
        }

        for (int i = 0; i < numeroDeRenas; i++) {
            threads.add(new Thread(new Rena(i)));
        }

        System.out.println("<--------- INÍCIO --------->");
        for (Thread t : threads) {
            t.start();
        }
    }

    static class Mensagem implements Runnable {
        String texto;
        Mensagem(String texto) {
            this.texto = texto;
        }
        @Override
        public void run() {
            System.out.println(texto);
        }
    }

    static class Amarracao implements Runnable {
        boolean trenoPreparado;
        Amarracao() {
            trenoPreparado = false;
        }
        @Override
        public void run() {
            trenoPreparado = !trenoPreparado;
            if (trenoPreparado) {
                System.out.println(">>> Renas amarradas e prontas!");
            } else {
                System.out.println(">>> Entrega realizada, renas desamarradas.\n    Férias das renas iniciadas!");
            }
        }
    }

    class Elfo implements Runnable {

        int id;

        Elfo(int id) {
            this.id = id;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(numeroAleatorio.nextInt(3000));

                while (true) {
                    filaDeElfos.acquire();
                    System.out.println("> Elfo " + id + " está com problemas...");

                    int elfo = tresElfos.await();
                    if (elfo == terceiroElfo) {
                        System.out.println("> Papai Noel está ajudando os elfos...");
                        atencaoDoPapaiNoel.acquire();
                    }

                    Thread.sleep(numeroAleatorio.nextInt(1000));
                    System.out.println("> Problema do elfo " + id + " resolvido!");
                    problemaResolvido.await();

                    if (elfo == terceiroElfo) {
                        atencaoDoPapaiNoel.release();
                    }
                    filaDeElfos.release();

                    Thread.sleep(numeroAleatorio.nextInt(2500));
                }
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

    class Rena implements Runnable {

        int id;

        Rena(int id) {
            this.id = id;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(4000 + numeroAleatorio.nextInt(500));
                    System.out.println("> Rena " + id + " voltou de suas férias no Caribe.");

                    int rena = noveRenas.await();
                    if (rena == ultimaRena) {
                        atencaoDoPapaiNoel.acquire();
                        System.out.println(">>> Entrega de Natal iniciando...");
                    }

                    treno.await();
                    Thread.sleep(numeroAleatorio.nextInt(150));

                    rena = treno.await();
                    if (rena == ultimaRena) {
                        atencaoDoPapaiNoel.release();
                        System.out.println(">>> Todos os brinquedos foram entregues!!!");
                    }
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        new PapaiNoel();
    }

}

Na última aula, meu professor comentou que seriam necessárias vinte threads no mínimo. Essa solução utiliza dezenove (dez elfos e nove renas). Como posso fazer com que a solução tenha o Papai Noel como mais uma thread? Eu gostaria que fosse assim para ter um maior controle da prioridade das renas sobre os elfos, e talvez colocar um tempo que o Papai Noel levaria para acordar e ir até a porta de sua loja (?). Se eu colocar o Papai Noel como Runnable também, o que ele vai fazer? O que vai ter nessa thread? Tô meio perdido hahaha

Criado 29 de agosto de 2019
Respostas 0
Participantes 1