Inversion de priorité
L'inversion de priorité est un phénomène qui peut se produire en programmation concurrente. Il s'agit d'une situation dans laquelle un processus de haute priorité ne peut pas avoir accès au processeur car il est utilisé par un processus de plus faible priorité.
Exemples
Pour les exemples, nous utiliseront des tâches A, B, et C, A ayant la plus forte priorité, C la plus faible, et B une priorité intermédiaire, et un mutex X qui sert à gérer une ressource partagée entre la tâche A et la tâche C.
Le premier exemple d'inversion de priorité est le plus simple: il ne fait intervenir que les tâches A et C et le mutex X. Par exemple, avec la séquence d'opération suivante :
- La tâche C (de basse priorité) acquiert le mutex X.
- Un événement réveille la tâche A (de forte priorité), qui préempte la tâche C. Cette dernière n'a pas libéré le mutex X.
- La tâche A essaye d'obtenir le mutex ; comme il est déjà acquis par la tâche C, la tâche A est donc mise en attente.
La tâche de haute priorité n'a donc pas accès à la ressource processeur mais une tâche de basse priorité y a accès. Ce premier cas est souvent bien maîtrisé par les développeurs, car c'est à cela que sert un mutex: s'assurer qu'une seule tâche accède à la ressource à un instant donné. La solution consiste simplement à libérer le mutex le plus vite possible dans la tâche C.
L'inversion de priorité devient problématique lorsque l'on fait intervenir la troisième tâche de priorité intermédiaire.
- La tâche C s'exécute, et prend le mutex X.
- Un événement réveille la tâche B, qui préempte la tâche C. Cette dernière n'a pas libéré le mutex X.
- Un autre événement réveille la tâche A, qui préempte la tâche B. Mais quand elle demande à prendre le mutex X, elle est mise en attente, et la tâche B continue de s'exécuter.
Il en résulte une inversion des priorités, la tâche B continuant de s'exécuter jusqu'à son terme, puis C, et enfin A : la tâche de plus haute priorité s'exécute en dernier ! Ce deuxième exemple est plus difficile a anticiper et à appréhender, car la tâche B bloque la tâche A alors qu'elles ne partagent aucune ressource.
Effets de l'inversion de priorité
La non gestion de l'inversion de priorité peut avoir des effets désastreux. En effet, comme l'exécution d'une tâche de haute priorité est retardée par des tâches moins prioritaires, il est possible qu'une réaction à des situations d'urgence ne soit pas prise en compte (par exemple, un ordre d'arrêt d'urgence d'une centrale nucléaire qui serait bloqué par un autre ordre de moindre priorité).
Méthodes pour éviter l'inversion de priorité
Il n'existe pas de solution simple permettant d'éviter toutes les inversions de priorité. Il est néanmoins possible de prendre des mesures pour limiter ces risques. En particulier, il est possible de
- n'autoriser l'accès à des sections critiques qu'à des threads de même priorité ;
- utiliser des sémaphores adaptés, par exemple des sémaphores à héritage de priorité ou des sémaphores à priorité plafond.
Ces sémaphores particuliers (qui sont nécessairement des mutex) accordent momentanément à la tâche qui les obtient la même priorité que celle de A (ou une priorité plus forte) afin de libérer la ressource au plus vite. Ainsi, dans le deuxième exemple, lorsque A est bloquée en attente du mutex X, C est autorisée à préempter B, elle libère alors le mutex X et est aussitôt préemptée par A. L'exécution se poursuit ensuite normalement avec B puis C.