mirror of
https://github.com/davidalves04/Trabalho-Pratico-SD.git
synced 2025-12-07 20:16:36 +00:00
personal branch
This commit is contained in:
175
TODO.md
Normal file
175
TODO.md
Normal file
@@ -0,0 +1,175 @@
|
||||
### Compreender os Conceitos Fundamentais
|
||||
|
||||
Primeiro, as tecnologias e paradigmas chave necessários para este projeto devem ser totalmente compreendidos.
|
||||
|
||||
- **Processos vs. Threads:** O projeto especifica o uso de ambos.
|
||||
|
||||
- **Processos (para Cruzamentos)** são programas independentes, cada um com o seu próprio espaço de memória. Em Java, cada cruzamento será provavelmente executado como uma aplicação Java separada (uma instância distinta da JVM).
|
||||
|
||||
- **Threads (para Semáforos)** existem _dentro_ de um processo e partilham memória. Isto é adequado para os semáforos, pois eles precisam de ser coordenados e partilhar dados (como filas de veículos) dentro do mesmo cruzamento.
|
||||
|
||||
- **Comunicação Entre Processos (IPC - Inter-Process Communication):** Como os cruzamentos são processos separados, é necessário um método para que eles comuniquem. **Sockets** são o método especificado. Quando um veículo sai de um cruzamento (ex: `Cr1`) e vai para outro (ex: `Cr2`), o processo `Cr1` precisa de enviar uma mensagem contendo os dados do veículo para o processo `Cr2` através de uma conexão por socket.
|
||||
|
||||
- **Simulação de Eventos Discretos (DES - Discrete-Event Simulation):** Este é o paradigma de simulação que deve ser utilizado. Em vez de o tempo fluir continuamente, o relógio da simulação salta de um evento para o seguinte.
|
||||
|
||||
- Um **evento** é um objeto que representa algo que acontece num ponto específico no tempo (ex: "Veículo A chega ao Cr2 no tempo 15.7s").
|
||||
|
||||
- Uma **lista de eventos** central, frequentemente uma fila de prioridades, será necessária para armazenar eventos futuros, ordenados pelo seu timestamp. O ciclo principal da simulação retira o próximo evento da lista, processa-o e adiciona quaisquer novos eventos que resultem dele.
|
||||
|
||||
- **Processo de Poisson:** Para o modelo "mais realista" de chegadas de veículos, é especificado um processo de Poisson. A principal conclusão é que o tempo _entre_ chegadas consecutivas de veículos segue uma **distribuição exponencial**. Em Java, este intervalo pode ser gerado usando `Math.log(1 - Math.random()) / -lambda`, onde `lambda` (λi) é a taxa de chegada especificada.
|
||||
|
||||
|
||||
---
|
||||
|
||||
### Uma Sugestão de Arquitetura de Alto Nível
|
||||
|
||||
Abaixo, é apresentada uma possível estrutura para a aplicação distribuída. Pode ser vista como um conjunto de programas independentes que comunicam através de uma rede.
|
||||
|
||||
1. **Processo Coordenador/Gerador (1 Processo):**
|
||||
|
||||
- **Propósito:** Iniciar a simulação, gerar veículos e gerir o relógio global da simulação ou os critérios de paragem.
|
||||
|
||||
- **Responsabilidades:**
|
||||
|
||||
- Lê a configuração da simulação (ex: carga de tráfego λi, tempos dos semáforos).
|
||||
|
||||
- Gera veículos de acordo com o modelo selecionado (intervalo fixo ou processo de Poisson).
|
||||
|
||||
- Atribui a cada novo veículo um percurso com base na distribuição uniforme especificada.
|
||||
|
||||
- Injeta o veículo no sistema enviando uma mensagem para o primeiro processo de cruzamento no seu percurso (ex: de um ponto de entrada E1 para Cr1).
|
||||
|
||||
2. **Processos de Cruzamento (5 Processos):**
|
||||
|
||||
- **Propósito:** Simular cada cruzamento (`Cr1` a `Cr5`) como um processo distinto.
|
||||
|
||||
- **Responsabilidades:**
|
||||
|
||||
- Escuta por veículos a chegar de outros processos.
|
||||
|
||||
- Gere as filas de veículos para os seus semáforos.
|
||||
|
||||
- Executa múltiplas **threads de Semáforo** internamente.
|
||||
|
||||
- Coordena estas threads para garantir que apenas uma direção de tráfego está aberta a cada momento.
|
||||
|
||||
- Quando um veículo atravessa, é encaminhado para o processo seguinte no seu percurso.
|
||||
|
||||
- Envia periodicamente as suas estatísticas (ex: comprimentos atuais das filas) para o Servidor do Dashboard.
|
||||
|
||||
3. **Processo de Nó de Saída (1 Processo):**
|
||||
|
||||
- **Propósito:** Representar o ponto de saída `S` e atuar como um coletor de dados para estatísticas globais.
|
||||
|
||||
- **Responsabilidades:**
|
||||
|
||||
- Recebe veículos que completaram o seu percurso.
|
||||
|
||||
- Calcula métricas globais como o tempo total de viagem (tempo de permanência) para cada veículo.
|
||||
|
||||
- Agrega e calcula as estatísticas finais (ex: tempo de viagem mínimo, máximo e médio por tipo de veículo).
|
||||
|
||||
- Envia estas estatísticas globais para o Servidor do Dashboard.
|
||||
|
||||
4. **Processo do Servidor do Dashboard (1 Processo):**
|
||||
|
||||
- **Propósito:** Agregar e exibir todos os dados da simulação em tempo real.
|
||||
|
||||
- **Responsabilidades:**
|
||||
|
||||
- Abre um socket de servidor e escuta por dados a chegar de todos os processos de Cruzamento e de Saída.
|
||||
|
||||
- Armazena e atualiza as estatísticas à medida que chegam.
|
||||
|
||||
- Apresenta os dados numa interface de utilizador, que deve exibir métricas e ser atualizada durante a simulação.
|
||||
|
||||
|
||||
---
|
||||
|
||||
### Plano
|
||||
|
||||
Nem tudo deve ser construído de uma só vez. Os seguintes passos incrementais são recomendados.
|
||||
|
||||
#### **Passo 1: Modelação e Classes Principais (Não-distribuído)**
|
||||
|
||||
Antes de escrever qualquer lógica complexa, as estruturas de dados devem ser definidas. Devem ser criados Plain Old Java Objects (POJOs) para:
|
||||
|
||||
- `Veiculo`: Com atributos como um identificador único, tipo, tempo de entrada e o percurso realizado. Deve ser tornado `Serializable` para que possa ser enviado através de sockets.
|
||||
|
||||
- `Evento`: Com atributos como um timestamp e o tipo de evento (ex: `VEHICLE_ARRIVAL`), bem como dados associados.
|
||||
|
||||
- `Semaforo`: Para conter o seu estado (`VERDE`/`VERMELHO`) e a fila de veículos.
|
||||
|
||||
- `Cruzamento`: Para conter os seus semáforos e a lógica operacional.
|
||||
|
||||
|
||||
#### **Passo 2: Construir um Protótipo de Processo Único**
|
||||
|
||||
Este é um passo crucial. Sockets e processos devem ser deixados de lado por agora para construir toda a simulação numa única aplicação Java.
|
||||
|
||||
- Deve ser criado um ciclo de simulação central baseado numa fila de prioridades para objetos `Evento`.
|
||||
|
||||
- Todos os objetos `Cruzamento` e `Semaforo` devem ser instanciados.
|
||||
|
||||
- A lógica principal deve ser tornada funcional: veículos a moverem-se entre filas, semáforos a mudar de estado e estatísticas básicas a serem recolhidas.
|
||||
|
||||
- **Objetivo:** Uma simulação totalmente funcional e não-distribuída. Isto torna a depuração significativamente mais fácil.
|
||||
|
||||
|
||||
#### **Passo 3: Distribuir os Cruzamentos**
|
||||
|
||||
O protótipo pode agora ser convertido num sistema distribuído.
|
||||
|
||||
- A classe `Cruzamento` deve ser tornada executável como uma aplicação Java autónoma (com um método `main`). Serão lançadas cinco instâncias, uma para cada cruzamento.
|
||||
|
||||
- Devem ser configurados sockets TCP para comunicação. Cada processo de cruzamento precisa de saber o endereço/porta dos vizinhos para os quais pode enviar veículos.
|
||||
|
||||
- Um **protocolo de comunicação** claro deve ser definido. Por exemplo, quando `Cr1` envia um veículo para `Cr2`, o objeto `Veiculo` é serializado e escrito no socket conectado a `Cr2`. O processo `Cr2` terá uma thread dedicada para escutar estas conexões de entrada.
|
||||
|
||||
|
||||
#### **Passo 4: Implementar as Threads dos Semáforos**
|
||||
|
||||
Dentro de cada processo `Cruzamento`, os semáforos devem ser implementados como threads.
|
||||
|
||||
- O principal desafio aqui é a **sincronização**. As threads dos semáforos num único cruzamento partilham as filas de veículos.
|
||||
|
||||
- As ferramentas de concorrência do Java (como `synchronized`, `ReentrantLock`, `Semaphore`) devem ser usadas para garantir que apenas um semáforo pode estar verde para um percurso conflituante e que o acesso às filas partilhadas é seguro (thread-safe).
|
||||
|
||||
|
||||
#### **Passo 5: Implementar o Dashboard**
|
||||
|
||||
- O processo `DashboardServer` deve ser criado. Ele irá escutar numa porta específica por estatísticas a chegar.
|
||||
|
||||
- Nos processos `Cruzamento` e `Saida`, deve ser adicionado um mecanismo para enviar periodicamente um resumo das suas estatísticas atuais para o Servidor do Dashboard.
|
||||
|
||||
- A UI deve ser construída para exibir estes dados em tempo real.
|
||||
|
||||
|
||||
#### **Passo 6: Testes e Análise**
|
||||
|
||||
Assim que o sistema completo estiver a funcionar, as experiências exigidas pela descrição do projeto podem ser realizadas.
|
||||
|
||||
- A simulação deve ser executada com diferentes taxas de chegada de veículos para simular cargas baixas, médias e altas.
|
||||
|
||||
- Diferentes políticas de temporização dos semáforos devem ser testadas para medir o seu impacto no congestionamento.
|
||||
|
||||
- Diferentes algoritmos de seleção de percurso e o seu impacto no desempenho do sistema devem ser avaliados.
|
||||
|
||||
- Para cada cenário, a simulação deve ser executada várias vezes para recolher estatísticas fiáveis (médias, desvios padrão, intervalos de confiança), conforme solicitado.
|
||||
|
||||
|
||||
#### **Passo 7: Escrever o Relatório**
|
||||
|
||||
À medida que cada passo é concluído, deve ser documentado. Isto tornará a escrita do relatório final muito mais fácil. Todos os pontos mencionados nas secções "Entrega" e "Critérios de Avaliação" devem ser abordados.
|
||||
|
||||
---
|
||||
|
||||
### OBS:
|
||||
|
||||
- **Começar de Forma Simples:** O protótipo de processo único (Passo 2) evitará grandes dificuldades mais tarde.
|
||||
|
||||
- **Protocolo de Comunicação:** O protocolo de mensagens deve ser definido o mais cedo possível. A informação exata que um processo envia para outro deve ser clara//simples//consistente.
|
||||
|
||||
- **Debugging:** Debugging de sistemas distribuídos podem ser difíceis. Uma framework de logging (como Log4j 2 ou SLF4J) pode ser usada para registar eventos//alterações de estado nos diferentes processos.
|
||||
|
||||
- **Configuração:** Valores como endereços IP, números de porta ou parâmetros da simulação não devem ser "hardcoded". Um ficheiro de configuração (ex: um ficheiro `.properties` ou `.json`) torna a aplicação mais fácil de executar e testar.
|
||||
@@ -1,34 +0,0 @@
|
||||
package sd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
public class CruzamentoServer {
|
||||
public static void main(String[] args) {
|
||||
// ... Inicializa Semáforos (Threads) ...
|
||||
// ... Inicializa as Estruturas de Dados ...
|
||||
|
||||
try (ServerSocket serverSocket = new ServerSocket(portaDoCruzamento)) {
|
||||
while (true) {
|
||||
Socket clienteSocket = serverSocket.accept();
|
||||
// Cria uma Thread de atendimento para lidar com o Veículo/Cliente
|
||||
new Thread(new AtendenteVeiculo(clienteSocket)).start();
|
||||
}
|
||||
} catch (IOException e) { /* ... */ }
|
||||
}
|
||||
|
||||
// Método chamado pelo AtendenteVeiculo para gerenciar o tráfego
|
||||
public synchronized boolean tentarPassar(Veiculo veiculo, String direcao) {
|
||||
// 1. Veículo entra na fila da direção
|
||||
// 2. Verifica o estado do semáforo da direção:
|
||||
Semaforo semaforo = getSemaforo(direcao);
|
||||
semaforo.esperarPeloVerde(); // O Veículo fica bloqueado se for vermelho
|
||||
|
||||
// 3. Após o verde:
|
||||
// - Remove da fila
|
||||
// - Permite a passagem (envia resposta de volta ao Veículo cliente)
|
||||
// 4. Envia estatística de passagem ao Simulador Principal (Cliente TCP)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
7
main/src/main/java/sd/Entry.java
Normal file
7
main/src/main/java/sd/Entry.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package sd;
|
||||
|
||||
public class Entry {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello, World!");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package sd;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello world!");
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package sd;
|
||||
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
public class Semaforo extends Thread {
|
||||
// ... atributos ...
|
||||
private final Lock semaforoLock; // Para sincronizar acesso ao estado
|
||||
private final Condition verdeCondition; // Para Veículos esperarem pelo verde
|
||||
|
||||
public Semaforo(...) {
|
||||
this.semaforoLock = new ReentrantLock();
|
||||
this.verdeCondition = semaforoLock.newCondition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
// Ciclo de tempo (ajustável para controle)
|
||||
estado = Estado.VERMELHO;
|
||||
// Notificar o Cruzamento sobre o estado
|
||||
try {
|
||||
Thread.sleep(tempoVermelho);
|
||||
estado = Estado.VERDE;
|
||||
// Ao ficar VERDE, notifica as threads Veículo que estão esperando
|
||||
semaforoLock.lock();
|
||||
try {
|
||||
verdeCondition.signalAll();
|
||||
} finally {
|
||||
semaforoLock.unlock();
|
||||
}
|
||||
Thread.sleep(tempoVerde);
|
||||
} catch (InterruptedException e) { /* ... */ }
|
||||
}
|
||||
}
|
||||
// Método para a thread Veículo esperar
|
||||
public void esperarPeloVerde() throws InterruptedException {
|
||||
semaforoLock.lock();
|
||||
try {
|
||||
if (estado == Estado.VERMELHO) {
|
||||
verdeCondition.await();
|
||||
}
|
||||
} finally {
|
||||
semaforoLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package sd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
public class Veiculo implements Runnable {
|
||||
// ...
|
||||
private String proximoCruzamentoIP;
|
||||
private int proximoCruzamentoPorta;
|
||||
|
||||
public void run() {
|
||||
// Simular o movimento na rua (Thread.sleep(t))
|
||||
|
||||
// 1. Tenta se conectar ao próximo Cruzamento
|
||||
try (Socket socket = new Socket(proximoCruzamentoIP, proximoCruzamentoPorta);
|
||||
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
|
||||
ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) {
|
||||
|
||||
// Envia o objeto Veículo com a solicitação de passagem
|
||||
out.writeObject(this);
|
||||
|
||||
// 2. BLOQUEIA a Thread, esperando a resposta do Servidor/Cruzamento
|
||||
String permissao = (String) in.readObject();
|
||||
|
||||
if ("OK_PASSAR".equals(permissao)) {
|
||||
// Simular tempo de travessia do cruzamento (pequeno Thread.sleep())
|
||||
// Atualiza a rota (próximo nó)
|
||||
}
|
||||
|
||||
} catch (IOException | ClassNotFoundException e) { /* ... */ }
|
||||
// ... continua o loop da rota até a Saída (S) ...
|
||||
}
|
||||
}
|
||||
Binary file not shown.
BIN
main/target/classes/sd/Entry.class
Normal file
BIN
main/target/classes/sd/Entry.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user