1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|
Especificación | Modelado | Verificación | Implementación | Verificación | Análisis |
PARA QUÉ | QUÉ | CÓMO | |||
¿Cuál es el problema? | ¿Qué tiene que hacer el sistema? | ¿El modelo cumple la especificación? | ¿Cómo hace lo que tiene que hacer? (modelo refinado) | ¿La implementación cumple la especificación? | ¿Se cumplen los plazos en el caso peor? |
LTL, CTL | FSM / xFSM | nuXmv | fsm.h / fsm.c | nuXmv | Análisis del tiempo |
(model checking) | Ejecutivo cíclico / FreeRTOS / Reactor | (model checking) | de respuesta |
En el capítulo 7 de [Barry] se comentan varios métodos para garantizar que no hay desalojo cuando un proceso accede a un recurso compartido o realiza una operación crítica que no puede ser interrumpida. La más agresiva es el par de macros taskENTER_CRITICAL
y taskEXIT_CRITICAL
.
1taskENTER_CRITICAL(); 2// ... operaciones muy críticas 3taskEXIT_CRITICAL();
Este método inhibe todo tipo de interrupciones, incluida la relacionada con el tiempo. Esto quiere decir que ni siquiera el contador de ticks se actualiza. No es frecuente que sea necesario hacer esto. Es mucho más razonable inhibir el planificador mediante vTaskSuspendAll
y restaurarlo con xTaskResumeAll
.
1vTaskSuspendAll(); 2// ... operaciones muy críticas 3xTaskResumeAll();
En este caso las interrupciones siguen funcionando y el tiempo se actualiza correctamente pero el planificador está paralizado, con lo que no puede haber desalojos. El análisis del bloqueo máximo es bastante similar al caso del algoritmo de techo de prioridad inmediato, pero en este caso todas las tareas pueden ser bloqueadas por tareas menos prioritarias, no solo las que compiten por el mismo recurso. Cada tarea solo puede ser bloqueada una vez en un ciclo y su tiempo de bloqueo sería.
donde es el tiempo máximo de cómputo requerido en la región crítica de la tarea para acceder al recurso .
FreeRTOS incorpora también mutexes que implementan el algoritmo de herencia de prioridad. Se construyen igual que cualquier otro tipo de semáforo. El mismo semáforo debe usarse en todas las tareas que pretendan sincronizar los accesos a un mismo recurso.
1SemaphoreHandle_t mutex = xSemaphoreCreateMutex();
Diferentes tareas pueden usarlo para garantizar la exclusión mediante las funciones xSemaphoreTake
y xSemaphoreGive
:
1xSemaphoreTake(mutex, portMAX_DELAY); 2// ... operaciones sobre el recurso compartido 3xSemaphoreGive(mutex);
La constante portMAX_DELAY
determina que espera de forma indefinida hasta obtener el acceso al recurso. En código de producción no se recomienda hacer una espera indefinida. Para ello la función xSemaphoreTake
devuelve pdTRUE
si ha podido obtener acceso y pdFALSE
si ha expirado el timeout:
1if (xSemaphoreTake(mutex, delayInTicks) == pdTRUE) { 2 // ... operaciones sobre el recurso compartido 3 xSemaphoreGive(mutex); 4} 5else { 6 // ... no pudo obtener acceso, medidas alternativas 7}
Un mutex implementa automáticamente el algoritmo de herencia de prioridad y por tanto el bloqueo máximo corresponde a:
donde es el tiempo requerido por la tarea para acceder al recurso (0 si no lo accede).