Sincronización de acceso entre tareas, debes saber

Sincronización de acceso entre tareas, debes saber

En esta publicación de blog, aprenderá la importancia de la sincronización de acceso entre tareas. Discutiremos la condición de carrera con su solución, incluida la exclusión mutua y el semáforo. Entonces, comencemos la publicación del blog de sincronización de acceso entre tareas con algunos problemas y sus soluciones.

El objetivo:recurso compartido

Shared Resource es un recurso compartido globalmente que está disponible para múltiples contextos. Ejemplos de recursos compartidos son la memoria global y los dispositivos periféricos. Por memoria global, me refiero a un dato, ya sea una variable global o una estructura de datos global. Además, las funciones globales que no son seguras para subprocesos se pueden considerar como memoria global (a menudo pasadas por alto por los programadores).

El problema:condición de carrera

La condición de carrera en el software surge cuando el resultado final depende de la secuencia de ejecución de las tareas. Su efecto es grave cuando los programadores no pretenden la secuencia de ejecución y no se predicen los resultados.

En un entorno puramente no preventivo, donde se emplea el sondeo de IO, el problema no existe.

Agregando interrupciones, introdujo el problema. Un ISR podría manipular un recurso compartido al que actualmente acceden tareas interrumpidas. ¡¡Boom, corrupción de datos!!

Por analogía con los ISR, agregar preferencia empeora el problema. Las tareas de mayor prioridad, además de los ISR, podrían manipular los recursos compartidos a los que actualmente accede la tarea reemplazada.

La solución:exclusión mutua

Las condiciones de carrera podrían evitarse si el acceso a los recursos compartidos fuera atómico. Ningún otro contexto se adelantará/interrumpirá el contexto actual durante el acceso. Desafortunadamente, el acceso no es atómico.

La otra forma de evitar las condiciones de carrera es garantizar que se acceda exclusivamente a los recursos compartidos. Independientemente de la preferencia/interrupción, se permite el acceso de un solo contexto al recurso compartido. Este mecanismo se conoce como Bloqueo.

Diferentes Soluciones:Diferentes Cerraduras

Los bloqueos difieren según el código de interrupción. Si está escribiendo un fragmento de código, debe:

  1. Identifique la naturaleza del código que está escribiendo (tarea, RTOS o ISR)
  2. Identifique los recursos compartidos en su código.
  3. Identifique el código de mayor prioridad que podría interrumpir/apropiarse (tarea, RTOS o ISR) de su código y acceder a los recursos compartidos identificados en el paso 2.
  4. Identifique los bloqueos adecuados y proteja los recursos compartidos.

Haciendo referencia a la figura 2, un ISR podría interrumpir a otro ISR, el RTOS o una tarea. Para proteger su código de ISR de mayor prioridad, se usa un bloqueo simple, habilitando y deshabilitando interrupciones .

El RTOS controla la ejecución de tareas. Si una tarea quiere evitar la preferencia al acceder a los recursos compartidos, debe deshabilitar y habilitar el programador.

Si el recurso compartido se comparte entre un grupo de tareas, se utilizan diferentes bloqueos. Estos son el semáforo y el mutex (descrito más adelante).

Si es un principiante y está buscando un buen curso en línea sobre RTOS, le recomiendo que consulte "Introducción al sistema operativo en tiempo real (RTOS)". Este curso está preparado por Amr Ali exclusivamente para principiantes. El curso contiene conferencias en video de 3 horas de duración con 2 recursos descargables que cubren todos los temas básicos de RTOS.

Inscríbase en el curso

Protección contra interrupciones

Deshabilitar y habilitar interrupciones no es tan simple como parece.

Un efecto secundario del uso de este mecanismo es la latencia de interrupción . Durante el acceso a los recursos compartidos, las interrupciones están deshabilitadas, lo que aumenta la latencia de interrupción. Como pauta, intente que el acceso a sus recursos compartidos sea lo más breve posible.

El código de acceso a los recursos compartidos no debe depender de la interrupción que esté deshabilitando . De lo contrario, su código fallará.

Además, tenga en cuenta que el uso de este mecanismo puede cambiar el estado de interrupción sin querer . Esta situación puede ocurrir en la realidad si estos bloqueos se protegen recursivamente sin el conocimiento del programador, por ejemplo.

En la mayoría de los RTOS, como uCOS u OSEK, tienen una versión que admite la protección recursiva de recursos compartidos. La operación de bloqueo, en lugar de deshabilitar las interrupciones, almacena el estado de interrupción anterior y luego deshabilita la interrupción. La operación de desbloqueo luego restaura el estado de interrupción anterior, ya sea que esté habilitado o deshabilitado.

Figura 4:Izquierda:el bloqueo de interrupción de activación/desactivación simple puede alterar el estado de interrupción anterior después de la liberación del recurso compartido. Derecha:una protección mejorada contra el mecanismo de interrupción que conserva el estado de interrupción anterior después de la liberación del recurso compartido.

Protección del RTOS

Durante el acceso al recurso compartido, el programador está deshabilitado. El núcleo preventivo es temporalmente no preventivo.

El código de acceso a los recursos compartidos no debe depender del planificador que esté deshabilitando . De lo contrario, su código fallará.

Vale la pena mencionar que la protección contra interrupciones no requiere protección del RTOS y viceversa. Los puntos de programación en RTOS se pueden clasificar en dos categorías:programación a nivel de tarea y programación a nivel de interrupción.

Cuando deshabilita el programador, ambas categorías de programación se deshabilitan, mientras que pueden ocurrir interrupciones. Deshabilitar las interrupciones deshabilitará la programación de nivel de interrupción ya que los ISR no se ejecutarán. Sin embargo, la programación a nivel de tarea no se ve afectada.

Protección de Tareas – I:Semáforo

Un semáforo es un contador sin signo. Hay 2 tipos de semáforos. Contar el semáforo puede contar de cero a máximo. El otro tipo es binario semáforo. Puede contar de cero a 1.

Los semáforos binarios se pueden considerar como un tipo especial de semáforos de conteo. Algunos RTOS solo implementan semáforos de conteo y dejan que el programador los use como semáforos binarios.

La operación de bloqueo de semáforo intenta disminuir el recuento de semáforos si es mayor que cero. Una tarea que intente bloquear un semáforo de valor cero se bloqueará. Esto significa que alguien ya ha cerrado el candado y el acceso al recurso compartido protegido por el semáforo está prohibido. Se otorgará acceso. El recuento de semáforos aumenta con la operación de desbloqueo.

Los semáforos tienen diferentes casos de uso. Solo dos de ellos están relacionados con el problema de acceso a recursos compartidos. Los otros dos casos de uso están relacionados con el uso del semáforo como una bandera en lugar de un candado (más allá del alcance de este artículo).

Problemas con los semáforos

Los semáforos resuelven las condiciones de carrera entre tareas. Pero tienen problemas asociados:hambruna, punto muerto, y inversión de prioridad .

El hambre es una situación en la que una tarea de baja prioridad no tiene acceso a los recursos compartidos. Cada vez que esta tarea de baja prioridad intenta tomar el recurso compartido, se bloquea porque otra tarea de alta prioridad ya está tomando el recurso compartido. Una posible solución al hambre es un diseño adecuado (selección de prioridades adecuadas o algoritmos de programación)

Interbloqueo es una situación en la que dos o más tareas están esperando recursos entre sí. Una posible solución al interbloqueo es un diseño adecuado (bloqueo ordenado).

La inversión de prioridad es una situación en la que una tarea de alta prioridad se bloquea en una tarea de baja prioridad utilizando un recurso compartido protegido. Durante este bloqueo, una tarea de prioridad media (que no necesita el recurso compartido) puede terminar su trabajo antes que la tarea de prioridad alta.

Protección de Tareas – II:Mutex

La solución a la inversión de prioridad del semáforo fue la introducción de un mutex. Mutex es simplemente un semáforo binario que se usa para proteger un recurso compartido con un protocolo asociado. El objetivo principal del protocolo asociado es resolver el problema de inversión de prioridad. Dos protocolos son los más comunes:herencia de prioridad y límite de prioridad .

En la herencia de prioridad, a una tarea de baja prioridad se le asigna automáticamente la prioridad de una tarea de mayor prioridad cuando se bloquea en el mutex. La tarea de baja prioridad se reasigna a su prioridad original cuando libera el mutex.

En el techo de prioridad, a una tarea de baja prioridad se le asigna una prioridad de techo una vez que accede al mutex. La prioridad máxima debe ser mayor o igual que la prioridad más alta de las tareas que usan este mutex en particular. La tarea de baja prioridad se reasigna a su prioridad original cuando libera la exclusión mutua. En otras palabras, una tarea de baja prioridad hereda la prioridad máxima una vez que se bloquea la exclusión mutua.

Según el RTOS que esté utilizando, puede implementar uno o ambos de estos protocolos. Si está utilizando un RTOS que implementa ambos algoritmos, la siguiente comparación puede ser útil para seleccionar el protocolo adecuado.

Una nota final, en algunas implementaciones de exclusión mutua admiten el bloqueo recursivo. Una tarea que está bloqueando un mutex puede volver a bloquearlo.

Publicación recomendada

  • Preguntas de la entrevista de protocolo Can.
  • Introducción al protocolo HDLC.
  • 100 preguntas de la entrevista C.
  • Preguntas de la entrevista de C++.
  • Entrevista de sistema integrado Preguntas con respuestas
  • Preguntas de la entrevista I2C
  • Preguntas de la entrevista sobre RTOS.