Una solución al clásico problema de concurrencia, sincronización y gestión de recursos en C.
El desafío consiste en simular un escenario donde varios filósofos se sientan alrededor de una mesa redonda. Hacen tres cosas: comer, dormir y pensar.
- Hay un tenedor entre cada par de filósofos.
- Para comer, un filósofo necesita dos tenedores (el de su izquierda y el de su derecha).
- Esto genera una competencia por los recursos (tenedores) que debe gestionarse cuidadosamente para evitar:
- Deadlocks: Todos tienen un tenedor y esperan indefinidamente por el segundo.
- Data Races: Múltiples hilos intentan acceder y modificar la misma memoria simultáneamente.
- Muerte: Si un filósofo no come dentro de un tiempo límite (
time_to_die), muere y la simulación termina.
Mi solución utiliza hilos (threads) y mutexes para gestionar la concurrencia y el acceso a los recursos compartidos, priorizando la precisión y la limpieza de memoria.
- Hilos Independientes: Cada filósofo es un hilo que ejecuta su rutina cíclica (comer, dormir, pensar).
- Hilo Monitor: Implementación de un sistema de supervisión centralizado (Monitor) que vigila constantemente el estado de los filósofos. Esto garantiza que la muerte se detecte con precisión de milisegundos, independientemente de si el filósofo está bloqueado esperando un tenedor o durmiendo.
- Protección de Datos: Uso estricto de
pthread_mutexpara proteger todas las lecturas y escrituras de variables compartidas (comolast_mealo el estadoend_sim), garantizando 0 Data Races. - Gestión de Memoria: Limpieza total de memoria (
free) y destrucción de mutexes al finalizar, asegurando 0 Memory Leaks. - Optimización: Algoritmo de toma de tenedores basado en paridad (pares/impares) para maximizar la concurrencia y evitar bloqueos inmediatos.
Necesitas gcc y make instalados en tu sistema (entorno Linux/Unix).
Clona el repositorio y compila el proyecto ejecutando:
make
Esto generará el ejecutable philo.
El programa toma los siguientes argumentos numéricos:
./philo [num_philos] [time_to_die] [time_to_eat] [time_to_sleep] [num_meals]
| Argumento | Descripción |
|---|---|
num_philos |
Número de filósofos y tenedores. |
time_to_die |
Tiempo (en ms) máximo que puede pasar sin comer antes de morir. |
time_to_eat |
Tiempo (en ms) que tarda en comer. |
time_to_sleep |
Tiempo (en ms) que pasa durmiendo. |
num_meals |
(Opcional) Si todos los filósofos comen al menos estas veces, la simulación se detiene. |
Aquí tienes algunos casos comunes para testear la robustez del programa:
1. Caso de vida infinita (Nadie debe morir):
La simulación corre indefinidamente. Para detenerla, usa Ctrl + C.
./philo 5 800 200 200
2. Muerte asegurada: Un filósofo morirá rápidamente porque el tiempo de vida es muy corto en comparación con lo que tardan en comer.
./philo 4 310 200 100
3. Simulación con límite de comidas: La simulación se detiene sola cuando todos han comido 7 veces.
./philo 5 800 200 200 7
4. Caso borde (1 Filósofo): El filósofo coge un tenedor, espera y muere al no poder comer solo.
./philo 1 800 200 200
Este proyecto ha sido validado rigurosamente para asegurar estabilidad y rendimiento bajo estrés.
Norminette: Código conforme al estándar de estilo de 42.
Valgrind (Memcheck): Comprobado sin fugas de memoria (0 leaks).
valgrind --leak-check=full ./philo 5 800 200 200 7
Helgrind: Comprobado libre de condiciones de carrera (0 data races).
valgrind --tool=helgrind ./philo 4 410 200 200
- Creación y gestión de hilos con
pthread_create,pthread_join. - Sincronización mediante
mutex(init,lock,unlock,destroy). - Prevención de Deadlocks y Race Conditions.
- Gestión precisa del tiempo en sistemas Unix (
gettimeofday). - Monitorización de procesos concurrentes.
Hecho por [cayuso-f] para 42 School.
