Sobre átomos y relojes

La particularidad de las interrupciones es que se caracterizan (como su nombre lo indica) por interrumpir al procesador en cualquier momento, de forma indistinta, aunque a veces pareciera que lo hacen de forma intencional sobre la tarea que más nos complica. La razón fundamental de su existencia es permitir que el micro pueda atender eventos que no es conveniente estar esperando o consultando, y/o que deben ser atendidos rápidamente y sin demoras.

Cuidadosamente utilizadas, son un poderoso aliado, y hasta es posible armar esquemas de tareas múltiples asignando a cada tarea una interrupción periódica independiente.

Su uso indiscriminado puede generar más inconvenientes que beneficios; particularmente no es posible compartir variables o subrutinas sin tomar las debidas precauciones de accesibilidad, atomicidad y reentrabilidad.

Una interrupción puede ocurrir en cualquier momento, y si ocurre en medio de la actualización de una variable multi-byte puede causar (y de hecho lo hace) estragos a las demás tareas, que quedan con valores “parcialmente alterados”, que en el mundo real son valores incorrectos, y probablemente de peligrosa incoherencia para el software. Un ejemplo típico y frecuentemente olvidado, son las variables de temporización, o fecha y hora. El programa principal se pone alegremente a descomponerlas byte a byte, de forma de mostrar su contenido en el display, sin pensar que, si son actualizadas por interrupciones, éstas no tienen por qué ocurrir antes o después de nuestro acceso y no durante el mismo. Si se muestran los valores en un display no hay mayor problema, al cabo de un segundo volveremos a la normalidad, pero si esto va a un log o informe vamos a tener que dar muchas explicaciones, como en el ejemplo siguiente, en el que aparece un registro con casi un año de diferencia

Utilicé alguna vez un entorno orientado a microcontroladores que “para subsanar este inconveniente”, incorporaba el concepto de ‘variables compartidas’ (shared variables). Ante un acceso o modificación de una variable así definida, se produce una inhibición de las interrupciones durante el transcurso de la misma. El problema que encuentro en este tipo de enfoques es que esto es malo para la didáctica como los pull-ups y diodos de protección en los GPIOs (como ya he comentado en otro artículo), el usuario no entiende qué pasa, no sabe, no aprende. Además, accesos reiterados a este tipo de variables producen inhibiciones reiteradas en las interrupciones, lo que se traduce como variaciones en la latencia de atención de éstas.

Si bien en una variable multi-byte como la del ejemplo esto resulta más que evidente, lo mismo ocurre en una variable de 32-bits o de 16-bits en micros de 8-bits que no disponen de instrucciones para acceder a variables de 32-bits (la gran mayoría) o 16-bits. La atomicidad, es decir, la propiedad de acceder a la variable como una unidad indivisible, se pierde, y cuando los accesos a estas variables son compartidos por tareas asíncronas existe la posibilidad de que se superpongan y entonces ocurra lo que hemos visto.

Si el entorno para desarrollar en C que utilizamos incorpora signal.h, deberíamos encontrar allí la definición del tipo sig_atomic_t, que identifica un tamaño de variable que puede ser accedido de forma atómica. Caso contrario, y como recomendación en estos entornos, el usuario debe conocer el micro con el que opera y obrar en consecuencia.

En entornos multiprocesados aparecen además otros inconvenientes, los cuales no abordaremos aquí.

Corolario

Una interrupción puede ocurrir en cualquier momento, siempre que esté habilitada. La probabilidad de que suceda justo en el instante en que se está produciendo la lectura de una variable cuyo acceso no es atómico es bastante baja, particularmente si ésta es breve y ocurre de forma no sincronizada con las interrupciones, y de manera no frecuente. Sin embargo, es mayor que cero, y por ende, en un número lo suficientemente alto de repeticiones, es de esperarse que ocurra. El dejar librado el correcto funcionamiento de un equipo a la función de distribución de Poisson no debería ser considerada buena práctica de diseño…

Este post contiene algunos extractos del libro “El Camino del Conejo“, con permiso del autor.

Want to share this ?

Leave a Reply

Your email address will not be published. Required fields are marked *

Enter Captcha Here : *

Reload Image