Ordonnancement

Introduction

Dans tout système multitâches l'un (si ce n'est le) des problèmes centraux est celui de l'ordonnancement, c'est-à-dire la sélection à un instant donné du processus auquel le processeur sera alloué. C'est la composante du système assurant cette fonction, l'ordonnanceur (scheduler) qui permet de garantir une exécution concurrente de plusieurs tâches. Il est bien clair que les objectifs visés ne sont pas les mêmes selon la nature du système considéré et par suite les stratégies mises en oeuvre dans les ordonnanceurs de ces différents types de systèmes sont différents.
Le problème d'ordonnancement est encore plus délicat dans un système temps réel, car non seulement il faut résoudre le problème classique, mais il faut en plus tenir compte de la forte contrainte qu'est le temps réel. Pour cela, on utilise la priorité d'une tâche. Celle-ci est liée à son caractère plus ou moins critique.

Pour résumer, le contexte dans lequel on se place est donc le suivant:

Quelques notions de base

- Les processus ont au cours de leur existence différents états possibles. Citons les trois principaux:

- Quand l'opération a-t-elle lieu?

- Méthodes d'évaluation des algorithmes - Préemption / réquisition: elle correspond au fait d'interrompre autoritairement une tâche active pour allouer le processeur à une autre;

- Priorité: valeur numérique associée à une tâche permettant de classer les différents tâches selon leur importance. En général il s'agit de valeurs entières, les petites valeurs correspondant souvent aux grandes priorités.
Ces priorités peuvent être statiques (si elles sont fixées au lancement des tâches et ne sont pas modifiées par le système) ou dynamiques (si elles sont mises à jour périodiquement par le système).
Ainsi, typiquement, dans un système temps réel, les priorités sont fixes et reflètent le caractère critique des tâches. Dans les systèmes orientés sur le partage du temps, les priorités sont dynamiques: schématiquement la priorité d'un processsus y diminuera si le processus est gros consommateur de CPU et augmentera dans le cas contraire (ce qui favorisera les processus interactifs).

- Quantum/tranche de temps (time slicing): le temps est découpé en tranches et, à chaque tranche une interruption permet à l'ordonnanceur du système de reprendre le contrôle;

- Tourniquet (round robin): c'est la technique de base consistant à allouer alternativement le processeur à chacun des processus prêts pour une durée maximale correspondant au quantum de temps (elle sera inférieure pour les tâches s'endormant durant leur période d'activité).

Les algorithmes d'ordonnancement généraux

- Ordonnancement FCFS

L'algorithme FCFS (First-Come-First-Served) (premier arrivé, premier servi) est le plus simple des algorithmes d'ordonnancement.

- Ordonnancement SJF

L'algorithme SJF (Shortest-Job-First) (le plus court en premier)

Les algorithmes d'ordonnancement pour le temps-réel

- Ordonnancement cyclique

- L'ordonnancement HPF

L'algorithme HPF (Highest Priority First) repose sur des priorités statiques associées aux différentes tâches selon la méthode d'analyse monotone par taux (Rate-Monotonic Scheduling). Le principe en est le suivant:

Dans l'exemple ci-dessous (en cliquant sur l'image, une version animée en est donnée), les trois tâches ont des périodes respectives de 10, 15 et 35 unités de temps, soit des priorités respectives 0.1, 0.07 et 0.03. Le temps de traitement nécessaire à chacune de leur période est respectivement de 4, 4 et 12 unités de temps.

Au temps 35, la tâche T3 a consommé 10 des 12 unités de temps nécessaires au traitement et le temps correspondant à sa période, un nouvel exemplaire en est lancé provoquant probablement l'abandon du traitement de l'occurrence en cours de traitement avant que celui-ci n'ait donné de résultat.

- L'ordonnancement EDF

La stratégie EDF (Earliest-Deadline First) est basée sur des priorités dynamiques : une tâche est d'autant plus prioritaire que son échéance est proche.

- L'ordonnancement LLF

La stratégie LLF (Least-Laxity First) est une variante de EDF.

Exemples

- JAVA

Une thread Java hérite à sa création de la priorité de celle qui la crée (de la même manière qu'un processus hérite de la priorité de son processus père lors d'un fork). Cette priorité peut être modifiée ultérieurement en lui appliquant la méthode setPriority. Les priorités des threads sont comprises entre les valeurs MIN_PRIORITY et MAX_PRIORITY définies dans la classe Thread (1 pour MIN_PRIORITY, 10 pour MAX_PRIORITY et 5 comme priorité standard NORM_PRIORITY).
L'algorithme d'ordonnancement utilisé est un algorithme préemptif avec tourniquet sur les systèmes supportant le temps partagé (par tranchage du temps). De manière plus précise, une thread restera active jusqu'à ce que l'une des conditions suivantes soit réalisée:

- MACH

A chaque activité (thread) est associé en vue de sa prise en compte par l'ordonnanceur d'un couple formé de

Les activités sont tout d'abord ordonnées sur la base des clases d'ordonnancement. Puis à l'intérieur d'une classe d'ordonnancement la priorité est utilisé pour classer les activités. Ainsi une activité de la classe temps-réel sera toujours plus prioritaire qu'une activité de la classe temps partagé.

Le noyau de Mach est de manière standard configuré avec les politiques suivantes:

- CHORUS

Comme c'est le cas dans MACH, dans le système CHORUS une activité possède une classe d'ordonnancement et une priorité dans cette classe. D'un point de vue interne, une activité possède une priorité système comprise entre 0 (la plus grande priorité) et 255 (la plus petite).
Par défaut, une politique FIFO est appliquée:

Un autre module d'ordonnancement, plus complet, peut être utilisé de manière optionnelle. Dans ce cas, trois classes d'ordonnancement coexistent:

Remarque: on retrouve la même approche avec les deux classes FIFO et RR proposées dans l'interface POSIX pour les activités (les PTHREADS). Une troisième politique (TS) correspondant à l'ordonnancement temps partagé à la Unix y a été ajoutée.

- QNX

On y retrouve la même approche avec les deux classes FIFO et RR. Une troisième classe y a également été ajoutée (l'ordonnancement adaptatif) utilisé pour les aspects temps-partagé. Lorsqu'un processus (QNX a adopté le parti pris de ne pas utiliser le concept de threads) a consommé tout son quantum de temps, sa priorité est décrémentée (dégénérescence de priorité) et lorsqu'il s'endort, il reprend sa priorité initiale.
Cependant dans ce système basé sur un micro-noyau, le modèle client/serveur est largement utilisé pour le développement de nouvelles applications et services. Quelles que soit la politique d'ordonnancement adoptée pour ces applications, les clients s`exécutent généralement à une priorité inférieure à celle des serveurs. Dans ces conditions, si un client de faible priorité requiert un service d'un serveur de haute priorité en lui adressant un message, cette requête sera a priori traité avec la priorité élevée du serveur. Donc d'une certaine manière le client verra sa priorité augmentée. On peut imaginer qu'ainsi la requête non prioritaire s`exécutera au détriment d'applications plus prioritaires que le client (mais moins prioritaire que le serveur). C'est pour cette raison qu'il est possible pour un serveur de spécifier qu'il traitera les demandes avec la priorité de ses clients (client-driven priority). Finalement afin de pouvoir traiter une nouvelle demande plus prioritaire qui arriverait pendant le traitement d'une requête, la priorité de la requête sera adoptée immédiatement par le serveur pour poursuivre le traitement en cours.


Dernière mise à jour : 16 octobre 2002