Introduction to RTOS Part 7 - Semaphore | Digi-Key Electronics
¿Cómo funcionan los semáforos en la programación concurrente?
Introducción a los semáforos y mutexes
- En la lección anterior se comparó un mutex con una llave en una cafetería, que se utiliza para desbloquear y bloquear un baño compartido. Un semáforo también protege recursos compartidos, pero puede contar más de uno.
- La analogía del baño no es suficiente, ya que aunque tengas una llave, necesitarías otro mecanismo para saber si el baño está ocupado. Los mutexes únicos son necesarios para proteger baños individuales.
Funcionamiento básico de los semáforos
- Un semáforo permite que múltiples hilos accedan a una sección crítica, lo cual es útil como mecanismo de señalización más que permitir acceso simultáneo.
- Se establece un valor inicial y máximo para el semáforo; por ejemplo, si se quiere permitir tres tareas al mismo tiempo en una sección crítica.
- Cuando una tarea quiere acceder a un recurso compartido, verifica el valor del semáforo. Si es mayor que cero, decrementa su valor y entra en la sección crítica.
Ejemplo práctico de uso de semáforos
- Tres tareas pueden trabajar simultáneamente en la sección crítica mientras el valor del semáforo sea positivo. Si llega una cuarta tarea, se bloquea hasta que alguna tarea termine.
- Al finalizar su trabajo, cada tarea debe devolver el semáforo incrementando su valor nuevamente para permitir el acceso a otras tareas.
Limitaciones y mejores prácticas
- Aunque esta teoría sobre los semáforos es válida, rara vez se utilizan así debido a la necesidad de proteger recursos individuales dentro de las secciones críticas.
- Los semáforos son más efectivos como mecanismos de sincronización entre hilos en patrones como productor-consumidor.
Diseño productor-consumidor
- En este diseño, varias tareas añaden datos a un recurso compartido (como un buffer), mientras otras eliminan datos.
- El tamaño del recurso compartido puede limitarse ajustando el valor máximo del semáforo; si está lleno, no se pueden añadir más elementos.
Comparación entre mutexes y semáforos
- A diferencia de los mutexes que implican propiedad (una tarea posee el mutex mientras trabaja), los semáforos no implican tal propiedad; deben ser utilizados para señalar disponibilidad.
- Las implementaciones de objetos kernel como mutexes suelen incluir herencia de prioridad; esto no ocurre con los semáforos.
Herencia de Prioridad en Semáforos
Concepto de Herencia de Prioridad
- La herencia de prioridad en semáforos implica elevar automáticamente la prioridad de las tareas que sostienen bloqueos mutex para evitar que una tarea de mayor prioridad se bloquee durante mucho tiempo.
- Esta técnica ayuda a mitigar el problema del "inversión de prioridades", un tema que se abordará más adelante.
Diferencias entre Semáforos y Mutexes
- Un semáforo binario solo cuenta hasta uno, lo cual puede parecerse a un mutex, pero no son lo mismo; los semáforos son útiles en rutinas de servicio de interrupción.
- En estas rutinas, no es recomendable usar un mutex ya que podría bloquearse esperando recursos.
Terminología y Uso
- Los semáforos POSIX utilizan términos como "post" y "wait"; es importante consultar la documentación del sistema operativo para entender su vocabulario específico.
Implementación Práctica con Semáforos Binarios
Caso Práctico: Uso de Semáforo Binario
- Se propone crear un semáforo binario inicializado en cero, permitiendo que la función setup espere hasta que los parámetros sean leídos correctamente.
- Al ejecutar este código, se observa cómo el número ingresado se pasa a la tarea blink utilizando el semáforo como señalización.
Expansión a Semáforo Contador
- Se introduce un demo con un semáforo contador creado con cinco tareas; cada tarea copia contenido y lo imprime antes de eliminarse.
- Se utiliza un bucle for para generar nombres únicos para cada tarea y pasarles punteros al mensaje estructurado.
Desafío: Protección del Puerto Serial
Consideraciones sobre Recursos Compartidos
- El puerto serial no está protegido como recurso compartido, lo cual puede causar superposiciones en la salida.
- Se sugiere tratar las declaraciones serial.print como una sección crítica usando mutexes para mejorar la protección.
Proyecto Final: Buffer Circular Compartido
Estructura del Proyecto
- El proyecto involucra cinco tareas productoras que añaden valores a un buffer circular y dos consumidoras que leen desde él.
- Cada productor escribe su número tres veces en el buffer; el objetivo es proteger este buffer usando mutexes y semáforos.
Requerimientos Adicionales