Práctica 3: Venta de entradas concurrente en Rust
Fecha límite de entrega: 30 de noviembre de 2026
Lenguaje de trabajo: Rust (std::sync, std::thread, atomics, mutexes)
Código de inicio: 📥 p3.tgz
1. Objetivos de la práctica
- Diseñar e implementar una arquitectura de ticketing concurrente en Rust: Transformar un sistema secuencial de venta de entradas en una solución multihilo de alto rendimiento capaz de atender ráfagas masivas de compradores concurrentes sobre recintos con diferentes sectores y capacidades.
- Garantizar la consistencia estricta (Safety): Eliminar condiciones de carrera y asegurar la invariante de negocio fundamental: cero billetes duplicados, 100% de aforo vendido y ausencia de reservas huérfanas o perdidas.
- Minimizar la contención y maximizar el rendimiento (Throughput): Identificar cuellos de botella generados por cerrojos globales de grano grueso y diseñar estrategias de sincronización eficientes en memoria compartida.
- Prevenir interbloqueos (Deadlocks) y pérdidas de vivacidad (Liveness): Coordinar el ciclo de vida de los hilos compradores y la cola de espera para asegurar que el sistema progrese de forma continua y finalice limpiamente.
2. El problema: venta masiva de entradas y alta contención
Imagina el lanzamiento de entradas para un gran concierto o evento: miles de usuarios acceden simultáneamente para conseguir localidades en diferentes zonas del recinto (pistas de pie de admisión general, gradas con asientos numerados, etc.).
El problema es intrínsecamente concurrente: múltiples compradores consultan la disponibilidad, seleccionan asientos y confirman la compra al mismo tiempo. Sin los mecanismos de sincronización adecuados, aparecen graves problemas de concurrencia:
- Condiciones de carrera (Race Conditions): Venta duplicada del mismo asiento a dos usuarios distintos.
- Inconsistencias y pérdidas de plazas: Bloqueos temporales que nunca se liberan o entradas que quedan huérfanas.
- Cuellos de botella por grano grueso: Si se utiliza un único cerrojo global para todo el recinto, los hilos se serializan y el rendimiento colapsa.
El sistema modela una arquitectura web cliente-servidor:
- Frontend / Cliente (
simulation.rs): Modela las sesiones concurrentes de los usuarios compradores (consulta de sectores, selección de butacas, confirmación o arrepentimiento). Interactúa con el backend exclusivamente mediante cadenas de texto (String/&[String]), simulando una API web. - Backend / Motor de Reservas (
booking.rs): Implementa la lógica de disponibilidad, reserva provisional y venta definitiva. Debe garantizar la consistencia del estado del recinto en todo momento bajo acceso multihilo.
3. Código base de la práctica
Descarga el paquete comprimido con el proyecto inicial en Rust:
📥 p3.tgz
El paquete contiene la estructura del proyecto con la implementación secuencial de partida:
main.rs: Punto de entrada de la aplicación (no modificable). Carga la configuración, inicializa el recinto y ejecuta la simulación.config.rs: Parámetros de ejecución y utilidades de configuración (no modificable).simulation.rs: Flujo de compra por sesión (no modificable). Orquesta el proceso de interacción de cada comprador.booking.rs: Define el traitBooker(la interfaz que debe cumplir el motor de reservas) y la implementación secuencial de referencia (SequentialBooker).venue.rs: Modelo de datos del recinto, sectores y asientos.queue_manager.rs: Define el traitQueueManagery el esqueleto para orquestar los hilos enConcurrentQueueManager.algorithm_name.txt: Fichero de texto donde debes indicar el nombre o identificador de tu solución.
Compilación y ejecución:
# 1. Compilar en modo release (imprescindible para medir rendimiento real)
cargo build --release
# 2. Ejecutar sobre el recinto de prueba incluido
cargo run --release
El código de partida incluye un recinto de ejemplo con sectores de admisión general y sectores numerados para que puedas probar tu solución en local. Durante la evaluación automática se utilizarán distintas configuraciones y tamaños de recinto para medir la robustez y escalabilidad de tu algoritmo.
4. Descripción del trabajo a realizar
Tu labor consiste en transformar el sistema secuencial en una solución concurrente de alto rendimiento, manteniendo la corrección estricta y cumpliendo el contrato de la API:
4.1 Implementar ConcurrentQueueManager (en queue_manager.rs)
- Debe implementar el trait
QueueManager. - Coordinar un conjunto de hilos workers (o un pool de tareas) para procesar concurrentemente las sesiones de compra de los usuarios que llegan a la cola.
- Recolectar de forma segura todos los identificadores de tickets vendidos por las distintas sesiones y devolverlos en el método:
fn run(&mut self) -> Vec<String>
4.2 Implementar un Booker concurrente (en booking.rs o módulos adicionales)
- Debe implementar fielmente el trait
Booker. - Diseñar la sincronización interna para soportar acceso concurrente multihilo sin condiciones de carrera y minimizando la contención entre hilos.
- Puedes modificar
venue.rso añadir nuevos módulos auxiliares según el diseño de sincronización que elijas.
4.3 Flujo del proceso de compra por sesión (simulation.rs)
El módulo simulation.rs orquesta la simulación del comportamiento de cada comprador a través de los métodos de tu Booker:
- Consulta de sectores disponibles: Llama a
get_available_sectors()para conocer qué zonas disponen de aforo. - Selección de sector: El comprador elige un sector según sus preferencias e invoca
select_sector(§or). - Consulta de localidades disponibles: Invoca
get_available_seats(§or)para obtener la lista de identificadores disponibles en dicho sector. - Reserva provisional: El comprador elige aleatoriamente localidades e intenta bloquearlas temporalmente llamando a
select_seats(§or, &selected_seats). - Decisión del usuario:
- Si el usuario cambia de opinión (50% de probabilidad), libera las localidades provisionales mediante
deselect_seats(§or, &selected_seats)y prueba con otro sector. - Si el usuario confirma la compra, invoca
book_seats(§or, &selected_seats).
- Si el usuario cambia de opinión (50% de probabilidad), libera las localidades provisionales mediante
- Checkout definitivo:
- La llamada a
book_seatsconfirma definitivamente la reserva y debe devolver unResult<Vec<String>, String>con los identificadores únicos definitivos de las entradas vendidas. - Si la compra no puede completarse (por ejemplo, porque la reserva provisional expiró o hubo un conflicto entre compradores), el usuario sufre una penalización de reintento y pasa a su siguiente preferencia.
- La llamada a
5. Requisitos de la solución y restricciones
-
Restricciones de modificación de código:
- NO se pueden modificar:
main.rs,simulation.rsniconfig.rs. Durante la evaluación automática se utilizarán las versiones oficiales de estos archivos. - Puedes modificar y ampliar:
booking.rs,queue_manager.rs,venue.rsy crear los ficheros o submódulos auxiliares que requiera tu diseño.
- NO se pueden modificar:
-
Prohibición de dependencias adicionales:
- No se permite el uso de dependencias o crates externos adicionales. Toda la sincronización y concurrencia debe implementarse haciendo uso exclusivo de la biblioteca estándar de Rust (
std::sync,std::thread, atomics, mutexes, etc.). Durante la corrección automática se utilizará el entorno base oficial, por lo que cualquier dependencia externa introducida provocará un fallo de compilación.
- No se permite el uso de dependencias o crates externos adicionales. Toda la sincronización y concurrencia debe implementarse haciendo uso exclusivo de la biblioteca estándar de Rust (
-
Condiciones de correctitud:
- Cero ventas duplicadas: Cada entrada vendida debe ser única.
- Venta completa: Se debe vender exactamente el 100% de la capacidad del recinto.
- Ausencia de interbloqueos (deadlocks): El programa debe finalizar de forma limpia y determinista dentro del tiempo establecido.
-
Fichero de identificación del algoritmo:
- Debes incluir un fichero llamado
algorithm_name.txtque contenga una única línea con el nombre que identifique tu solución o algoritmo.
- Debes incluir un fichero llamado
6. Criterios de evaluación y entrega
La evaluación se realizará de forma 100% automática sobre una batería de recintos de prueba con distintas configuraciones y niveles de concurrencia.
Correctitud (Requisito indispensable)
En cada escenario de prueba se comprobarán estrictamente los siguientes requisitos:
- Cero ventas duplicadas: Ningún identificador de ticket puede haberse vendido más de una vez ().
- Venta completa: Se vende exactamente el 100% de la capacidad del recinto, sin localidades huérfanas ni bloqueos pendientes.
- Ausencia de interbloqueos (deadlocks): La ejecución debe finalizar limpiamente dentro del tiempo límite establecido.
- Cumplimiento del contrato: No se han alterado los ficheros protegidos (
main.rs,simulation.rs,config.rs).
Cualquier incumplimiento de las condiciones de correctitud en un escenario invalida la puntuación de dicho escenario.
Rendimiento concurrente
Entre todas las entregas que superen los requisitos de correctitud en un escenario, la calificación se determinará a partir del tiempo de ejecución y el rendimiento (throughput) obtenido:
- Las implementaciones con menor tiempo de ejecución y menor contención obtendrán la máxima calificación.
- El uso de la solución secuencial básica o de soluciones concurrentes con serialización total (bloqueos globales de grano grueso) penalizará fuertemente la calificación, ya que el objetivo fundamental de la práctica es el diseño de algoritmos concurrentes eficientes.
Formato y entrega
- La entrega se realiza a través de la plataforma pracdlsi.
- No es necesario entregar
Cargo.toml. - El archivo comprimido
p3.tgzdebe contener tu código fuente y tu fichero de identificación:booking.rsqueue_manager.rsvenue.rs(y ficheros auxiliares propios, si los has creado)algorithm_name.txt
- Para generar la entrega, coloca estos ficheros dentro de un directorio llamado
p3y comprímelo mediante el terminal:tar cfz p3.tgz p3 - Puedes entregar tantas veces como desees antes de la fecha límite; el sistema evaluará únicamente la última entrega registrada.