Implementación de un sistema concurrente en C bajo el estándar POSIX Threads (pthreads).
El proyecto demuestra sincronización controlada entre hilos mediante exclusión mutua (mutex), protocolo de lectura/escritura alternada sobre memoria compartida intra-proceso, cifrado modular de datos y finalización limpia mediante señales del sistema.
Archivo principal del proyecto:
thread_sync_manager.c
Adriano Scatena
- Descripción General
- Arquitectura del Sistema
- Resolución Técnica y Modelo de Sincronización
- Modelo Criptográfico Implementado
- Manejo de Señales y Finalización Controlada
- Diagrama de Flujo General
- Diagrama de Dinámica del Hilo A
- Compilación y Ejecución
- Consideraciones Técnicas
- Bibliografía
El programa implementa un arreglo compartido de 20 enteros accesible por dos hilos concurrentes:
- Hilo A
- Hilo B
El comportamiento del sistema sigue un protocolo determinístico:
- Hilo A escribe los primeros 10 elementos.
- Hilo B los lee únicamente cuando la escritura finaliza.
- Hilo B escribe los últimos 10 elementos.
- Hilo A los lee únicamente cuando la escritura finaliza.
- El ciclo se repite hasta que el hilo A recibe la señal
SIGTERM.
Restricción central del diseño:
Ningún hilo puede sobrescribir su zona hasta que el otro haya leído completamente los datos, excepto en la primera iteración.
- Estructura
shared_memorycon arreglo de 20 enteros. - Dos hilos creados mediante
pthread_create(). - Dos mutex independientes:
mutex_a→ protege los primeros 10 elementos.mutex_b→ protege los últimos 10 elementos.
- Variables de control compartidas:
lectAlectBsigtermsigstopsigcont
Al tratarse de hilos dentro del mismo proceso, la memoria es compartida directamente (mismo espacio de direcciones), por lo que no se requiere IPC a nivel kernel.
La sincronización del sistema se implementa mediante mutex (Mutual Exclusion), mecanismo fundamental en programación concurrente que garantiza que únicamente un hilo pueda acceder a una sección crítica en un momento dado.
El diseño evita condiciones de carrera en la escritura y lectura del arreglo compartido, ya que ambos hilos operan sobre una estructura común de memoria. Sin un mecanismo de exclusión mutua, podrían producirse inconsistencias de datos debido a accesos simultáneos.
Cada hilo administra su acceso a la sección crítica del siguiente modo:
- Solicita el bloqueo del
mutexcorrespondiente. - Si el
mutexestá disponible, lo adquiere y ejecuta la sección crítica. - Si el
mutexestá ocupado, el hilo entra en estado de bloqueo a nivel del sistema operativo (bloqueo de sincronización). - Finalizada la sección crítica, el hilo libera el
mutex.
Este comportamiento se implementa mediante:
pthread_mutex_lock()pthread_mutex_trylock()pthread_mutex_unlock()
Ejemplo representativo (escritura del Hilo A):
pthread_mutex_lock(&mutex_a);
printf("\nHilo A comenzó a escribir los primeros 10 elementos\n\n");
/* SECCIÓN CRÍTICA */
for (int i = 0; i < SIZE / 2; i++) {
int rnum = rand() % 27;
shm.datos[i] = cifrar(rnum);
sleep(1);
}
/* FIN SECCIÓN CRÍTICA */
pthread_mutex_unlock(&mutex_a);Mientras un hilo posee el mutex, ningún otro puede acceder a esa zona protegida.
Cuando otro hilo intenta bloquear un mutex ya adquirido, el sistema operativo lo suspende hasta su liberación, evitando consumo activo de CPU.
Este esquema garantiza:
- Coherencia de datos
- Acceso ordenado
- Ausencia de condiciones de carrera
- Alternancia controlada entre escritura y lectura
Los valores generados pertenecen al rango [0, 26], representando letras del alfabeto.
f(x) = (4x + 5) mod 27
f⁻¹(x) = (7x + 19) mod 27
Implementación:
int cifrar(int x) { return (4 * x + 5) % 27; }
int descifrar(int x) { return (7 * x + 19) % 27; }Se trata de un cifrado afín modular clásico, donde las constantes cumplen la condición de inversibilidad en módulo 27.
El cifrado se realiza antes de escribir en memoria compartida, y el descifrado al momento de la lectura.
La finalización del sistema se realiza mediante recepción de la señal SIGTERM en el hilo A:
signal(SIGTERM, handle_sigterm);El manejador:
void handle_sigterm(int signum) {
sigterm = true;
}Al activarse:
- Se modifica una bandera compartida.
- Ambos hilos abandonan su bucle
while(!sigterm). - Cada hilo finaliza mediante
pthread_exit(NULL).
El proceso principal sincroniza la finalización usando:
pthread_join(hiloA, NULL);
pthread_join(hiloB, NULL);Luego destruye los mutex:
pthread_mutex_destroy(&mutex_a);
pthread_mutex_destroy(&mutex_b);Este diseño garantiza:
- Terminación ordenada
- Liberación correcta de recursos
- Ausencia de hilos huérfanos
- Limpieza completa del entorno concurrente
flowchart TD
A[Inicio del programa]
A --> B[Inicialización de mutex]
B --> C[Creación de hilo A]
B --> D[Creación de hilo B]
C --> E[Dinamica A]
D --> F[Dinamica B]
E --> G{¿SIGTERM?}
F --> H{¿SIGTERM?}
G -->|No| EA[Escribir primeros 10\nmutex_a]
EA --> EB[Leer últimos 10\nmutex_b]
EB --> G
H -->|No| FA[Escribir últimos 10\nmutex_b]
FA --> FB[Leer primeros 10\nmutex_a]
FB --> H
G -->|Sí| I[Finalización controlada]
H -->|Sí| I
I --> J[Join de hilos]
J --> K[Destrucción de mutex]
K --> L[Fin del programa]
flowchart TD
A[Inicio dinamicaA]
A --> B{¿SIGTERM?}
B -->|No| C[Solicita mutex_a]
C --> D[Sección crítica:\nEscritura cifrada primeros 10]
D --> E[Libera mutex_a]
E --> F[Solicita mutex_b]
F --> G[Sección crítica:\nLectura descifrada últimos 10]
G --> H[Libera mutex_b]
H --> B
B -->|Sí| I[Finaliza hilo A]
gcc thread_sync_manager.c -o posix_threads_sync -pthread./posix_threads_syncDesde otra terminal:
kill -SIGTERM <PID>
kill -SIGUSR1 <PID>
kill -SIGUSR2 <PID>El PID se muestra al iniciar el programa.
Este proyecto evidencia:
- Dominio de programación concurrente en C.
- Comprensión del modelo de memoria compartida.
- Uso correcto de exclusión mutua en entornos POSIX.
- Interacción entre señales asincrónicas y ejecución multihilo.
- Finalización limpia y controlada de recursos compartidos.
- Modelado determinístico de protocolos de acceso a memoria.
-
IBM Documentation — Exclusión mutua y hebras
https://www.ibm.com/docs/es/i/7.5?topic=threads-mutexes -
pthread_join en C
https://www.delftstack.com/es/howto/c/pthread_join-return-value-in-c/ -
IEEE Std 1003.1-2017 — POSIX Threads Standard