diff --git a/README.md b/README.md index 8313a23..d2e9cdf 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,20 @@ co.eci.snake ### 1) Análisis de concurrencia - Explica **cómo** el código usa hilos para dar autonomía a cada serpiente. + +Respuesta: + +Exíte una clase llamada SnakeRunner que implementa runnable, eso quiere decir que la función de la clase +es decir qué tarea debe hacer el hilo. Esta clase tiene 5 atributos: `snake`, `board`, `baseSleepMs`, `turboSleepMs` y `turboTicks`. + +A continuación se mostrará lo que hace el hilo al iniciar: +1. Verifíca que el hilo no esté interrumpido. +2. Si no lo está entonces puede que la serpiente cambie de dirección en el tablero. +3. Si la serpiente choca contra un obstáculo, esta cambia de dirección de forma aleatoria. +4. Si la serpiente come un turbo entonces el tiempo en el que está dormido el hilo será menor por lo que la serpiente se mueve más rápido, pero con el tiempo vuelve a su velocidad normal. + +Cabe resaltar que cada serpiente corre su método run() en paralelo con los demás. + - **Identifica** y documenta en **`el reporte de laboratorio`**: - Posibles **condiciones de carrera**. - **Colecciones** o estructuras **no seguras** en contexto concurrente. @@ -148,3 +162,55 @@ Incluye compilación y ejecución de pruebas JUnit. Si tienes análisis estátic Este laboratorio es una adaptación modernizada del ejercicio **SnakeRace** de ARSW. El enunciado de actividades se conserva para mantener los objetivos pedagógicos del curso. **Base construida por el Ing. Javier Toquica.** + + + + +## REPORTE DE LABORATORIO +### 1) Análisis de concurrencia +**Cómo los hilos dan autonimía a cada serpiente** + +Exíte una clase llamada SnakeRunner que implementa runnable, eso quiere decir que la función de la clase +es decir qué tarea debe hacer el hilo. Esta clase tiene 5 atributos: `snake`, `board`, `baseSleepMs`, `turboSleepMs` y `turboTicks`. + +A continuación se mostrará lo que hace el hilo al iniciar: +1. Verifíca que el hilo no esté interrumpido. +2. Si no lo está entonces puede que la serpiente cambie de dirección en el tablero. +3. Si la serpiente choca contra un obstáculo, esta cambia de dirección de forma aleatoria. +4. Si la serpiente come un turbo entonces el tiempo en el que está dormido el hilo será menor por lo que la serpiente se mueve más rápido, pero con el tiempo vuelve a su velocidad normal. + +Cabe resaltar que cada serpiente corre su método run() en paralelo con los demás. + +**Condiciones carrera** + +Hay tres candidatos posibles: `res`, `turboTicks` y `board.step(snake)` + +- res: es una variable local dentro del hilo asi que cada hilo tiene un res diferente por lo que no sería una condición +carrera. +- turboTicks: en cada interación turboTicks está disminuyendo, así que esta si sería una variable mutable. El problema es que +la varaible no se comparte en cada hilo, es una variable "privada" de cada hilo. +- board.step(snake): puede ser una condición de carrera porque todas las serpientes, cada una manejada con un hilo, interactuan con un mismo tablero. + +- La clase **snake**: La clase es accedida concurrentemente por múltiples threads sin sincronización. + +**Colecciones o estructuras no seguras para hilos** + +- HashSet: La clase Board usa esta colección para almacenar `obstáculos`, `ratones` y `turbos`. + +¿Cuál es el inconveniente? + +El problema es que HashSet no es una colección segura para hilos. Cuando varias serpientes interactua al mismo tiempo con estas colecciones, pueden ocurrir condiciones de carrera. En el caso de los ratones, si una serpiente se come un ratón, el ratón debe ser +eliminado del Hash y además se debe poner un nuevo ratón aleatoriamente en el tablero y se debe agregar a la colección. Si otra serpiente modifíca la colección al mismo tiempo, puede que halla un resultado incosistente. + +- HashMap: la clase Board utiliza esta estructura de datos para guardar `teleports`. + +HashMap tampoco es thread-safe. Si no se protegiera adecuadamente, accesos concurrentes podrían causar inconsistencias en los pares de teletransporte. + + +**Sincronización innecesaria** +![Captura de pantalla 2026-02-05 113609.png](src/img/Captura%20de%20pantalla%202026-02-05%20113609.png) + +En la imagen podemos ver que estos métodos utilizan la palabra clave `synchronized`. Aunque estos métodos pueden ser llamados desde distintos hilos, no interactúan directamente con la lógica de +movimiento de las serpientes ni modifican el estado del tablero, por lo que su sincronización resulta innecesaria. + + diff --git a/src/img/Captura de pantalla 2026-02-05 113609.png b/src/img/Captura de pantalla 2026-02-05 113609.png new file mode 100644 index 0000000..a31d5f2 Binary files /dev/null and b/src/img/Captura de pantalla 2026-02-05 113609.png differ diff --git a/src/main/java/co/eci/snake/core/Board.java b/src/main/java/co/eci/snake/core/Board.java index be2cfe9..483e79e 100644 --- a/src/main/java/co/eci/snake/core/Board.java +++ b/src/main/java/co/eci/snake/core/Board.java @@ -31,7 +31,7 @@ public Board(int width, int height) { public int width() { return width; } public int height() { return height; } - public synchronized Set mice() { return new HashSet<>(mice); } + public synchronized Set mice() {return new HashSet<>(mice); } public synchronized Set obstacles() { return new HashSet<>(obstacles); } public synchronized Set turbo() { return new HashSet<>(turbo); } public synchronized Map teleports() { return new HashMap<>(teleports); } diff --git a/src/main/java/co/eci/snake/core/Direction.java b/src/main/java/co/eci/snake/core/Direction.java index fe1600d..9a9fecf 100644 --- a/src/main/java/co/eci/snake/core/Direction.java +++ b/src/main/java/co/eci/snake/core/Direction.java @@ -1,4 +1,10 @@ package co.eci.snake.core; -public enum Direction { UP(0,-1), DOWN(0,1), LEFT(-1,0), RIGHT(1,0); - public final int dx, dy; Direction(int dx, int dy){ this.dx=dx; this.dy=dy; } } +public enum Direction { + UP(0,-1), + DOWN(0,1), + LEFT(-1,0), + RIGHT(1,0); + public final int dx, dy; Direction(int dx, int dy){ + this.dx=dx; this.dy=dy; } +}