Práctica 1.1: Creación y Gestión de Procesos e Hilos
Fecha límite de entrega: 13 de octubre de 2026 a las 15:00
Lenguajes de trabajo: C (POSIX) y Rust
Código de inicio: 📥 mandelbrot_base.zip
1. Objetivos de la Práctica
- Comprender la diferencia física entre Memoria Compartida y Memoria Aislada: Experimentar el acceso nativo a memoria de los hilos (
pthread) frente al aislamiento de los procesos (fork()), resolviéndolo explícitamente con Memoria Compartida POSIX (mmap). - Identificar y resolver el Desequilibrio de Carga (Load Imbalance): Descubrir cómo la complejidad heterogénea del algoritmo afecta al rendimiento al usar un Reparto Estático por Bloques frente a un Reparto Intercalado / Cíclico.
- Automatización de procesos con
exec: Crear procesos hijos y reemplazar su imagen ejecutable medianteexecvp()para invocar herramientas del sistema tras el cálculo. - Concurrencia en Rust: Implementar la versión multihilo en Rust usando
std::thread::spawny comparar la ergonomía y seguridad del lenguaje.
2. Código base y visualización
Como caso de estudio para comparar la aceleración y la gestión de memoria, generaremos el fractal del conjunto de Mandelbrot ().

Descarga del código de partida
Descarga el paquete comprimido con el código secuencial de partida tanto para C como para Rust:
📥 mandelbrot_base.zip
El archivo contiene:
mandelbrot_base.c: Código base secuencial en C.mandelbrot_rust/: Proyecto de Cargo base secuencial en Rust.
Compilación y ejecución secuencial en C:
gcc -O2 mandelbrot_base.c -o mandelbrot_base -lm
./mandelbrot_base
Compilación y ejecución secuencial en Rust:
cd mandelbrot_rust
cargo run --release
Ambos programas generan una imagen mandelbrot.ppm en formato bruto PPM (Portable Pixmap).
Visualización y Conversión a PNG
Para poder visualizar fácilmente el resultado en cualquier visor de imágenes o navegador, puedes convertir manualmente el archivo .ppm a .png ejecutando en tu terminal:
ffmpeg -y -i mandelbrot.ppm mandelbrot.png
3. Ejercicios
Ejercicio 1: Implementación multi-hilo con hilos POSIX (pthread)
En este ejercicio implementarás una versión paralela en C usando la librería POSIX Threads (pthread.h) en el archivo mandelbrot_hilos.c. Todos los hilos compartirán el buffer global de píxeles Pixel img[HEIGHT][WIDTH].
Requisitos del programa:
- Debe recibir el número de hilos por línea de comandos (
./mandelbrot_hilos 4). - Debe distribuir las filas del fractal entre los hilos. Para comprobar el rendimiento en tu memoria, debes probar dos estrategias de reparto:
- Reparto estático por bloques: El Hilo 0 procesa las primeras filas, el Hilo 1 el siguiente bloque, etc.
- Reparto intercalado/cíclico: El Hilo procesa las filas donde (Round-Robin).
- Conversión automática con
fork-exec: Tras guardar el archivomandelbrot.ppmen disco, mediante los comandosforkyexecvpllama afmmpegautomáticamentemandelbrot.png. El proceso padre esperará la terminación del hijo de conversión mediantewait(NULL).
Cuestiones:
- ¿Por qué el reparto cíclico consigue un tiempo de ejecución significativamente menor que el reparto por bloques? (Piensa en la diferencia de iteraciones entre los píxeles del centro negro del fractal y los píxeles del fondo).
- Calcula el Speedup () para hilos en tu procesador y represéntalo en una tabla en tu memoria.
- ¿Qué ocurre con las líneas de código situadas después de la llamada a
execvp()en el proceso hijo de conversión? Explica por qué nunca llegan a ejecutarse si la llamada tiene éxito.
Ejercicio 2: Implementación multi-proceso con fork y memoria compartida
En este ejercicio implementarás el paralelismo usando procesos independientes con fork() en el archivo mandelbrot_procesos.c.
Apartado A: El Problema de la Memoria Aislada
Si intentas duplicar el código de hilos sustituyendo pthread_create por fork(), comprobarás que la imagen resultante sale completamente negra o vacía.
- Explicación: Al llamar a
fork(), el kernel clona el espacio de direcciones del padre (Copy-On-Write). Cuando un hijo escribe enimg[y][x], modifica su copia privada en memoria. El proceso padre conserva la memoria intacta.
Apartado B: Configuración de memoria compartida (shm_open + mmap)
Para que los procesos hijos puedan escribir en la matriz de la imagen final del padre:
- Crea un segmento de memoria compartida con
shm_open("/mandel_shm", O_CREAT | O_RDWR, 0666). - Establece su tamaño con
ftruncate(fd, sizeof(Pixel) * HEIGHT * WIDTH). - Mapea la región en el espacio de direcciones del proceso mediante
mmap()especificando el flagMAP_SHARED:Pixel *img_shm = mmap(NULL, sizeof(Pixel) * HEIGHT * WIDTH,PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - El proceso padre lanza los hijos con
fork(), los cuales heredan el punteroimg_shm. - Cada hijo calcula su franja de filas y escribe directamente en
img_shm. - El proceso padre espera a que todos los hijos terminen mediante
wait(NULL). - El padre guarda la imagen
.ppm, la convierte a.pngconexecvp, desmapea la memoria conmunmap()y la elimina conshm_unlink("/mandel_shm").
Cuestiones:
- Explica la diferencia entre el acceso a memoria compartida en
pthread(implícito) y enfork()conmmap(explícito). - ¿Qué ocurriría si se omitiera el flag
MAP_SHAREDen la llamada ammap()?
Ejercicio 3: Multi-Hilo en Rust (std::thread)
En este ejercicio implementarás la versión paralela del algoritmo en Rust dentro del proyecto mandelbrot_rust (en el archivo src/main.rs).
Requisitos del programa:
- Debe recibir el número de hilos como argumento por línea de comandos (
cargo run --release -- 4). - Utiliza
std::thread::spawnpara lanzar hilos que procesen las filas de la imagen. - Utiliza la cláusula
movepara pasar los datos necesarios a la closure de cada hilo y espera la finalización de todos los hilos con.join().unwrap(). - Guarda la imagen resultante.
Cuestiones:
- Compara la sintaxis y el manejo de hilos en Rust frente a C (
pthread). ¿Qué garantías ofrece el compilador de Rust (Borrow Checker) durante el desarrollo?
4. Entrega y Estructura del Repositorio
Debes entregar un archivo comprimido p1_1.tgz en la plataforma de prácticas conteniendo:
p1_1/
├── mandelbrot_hilos.c
├── mandelbrot_procesos.c
├── mandelbrot_rust/
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
└── memoria.pdf (o memoria.md)
En la memoria debes incluir las respuestas a todas las Cuestiones planteadas en cada ejercicio.