L'ordonnanceur est la fonction qui distribue le temps d'occupation du processeur central (CPU) aux processus. De prime abord, cela paraît simple : l'ordonnanceur fait tourner le tourniquet. Le tourniquet est la représentation imaginaire de la liste des processus dont on relierait les deux extrémités (le début et la fin) pour former un anneau.
L'ordonnanceur est un composant du noyau des systèmes d'exploitation, avec les privilèges les plus élevés (ring 0).
L'ordonnanceur à des fonctions diverses :
- L'ordonnanceur veille à ce qu'une application qui entre sur le tourniquet entre en dernier, sinon elle vole le temp de celle à qui c'est le tour (elle « affame » un autre processus qui était là avant elle (on parle de « famine »). Il faudrait des ordonnanceurs pour gérer les files d'attente aux caisses des grandes surfaces et veiller à ce que celui qui arrive ne passe jamais devant les autres.
- L'ordonnanceur gère le temps de possession d'un processeur par un processus. La possession du processeur n'est pas forcément le même pour chaque processus. Il y a le mécanisme de « priorités » plus ou moins élevées, qui permet de donner plus (ou moins) de temps à un processus, par rapport au temps normal alloué par défaut.
- L'ordonnanceur gère les interruptions sur attente d'événement. Un processus qui attend quelque chose le signale immédiatement à l'ordonnanceur. Par exemple, un processus peut demander (lire) ou écrire une donnée qui se trouve sur disque. Ceci est une opération extrêmement lente, même s'il s'agit d'un SSD, comparée à la vitesse des processeurs. La demande est passée à la fonction du noyau du système d'exploitation qui s'occupe de cela. Un drapeau (sémaphore) de suspension sur attente d'événement est positionné (à « vrai »). Le contexte d'exécution du processus suspendu est sauvegardé et l'« ordonnancement des processus » passe immédiatement la main au processus suivant sur le tourniquet, en restaurant son contexte d'exécution. Le processus en attente d'entrée/sortie ne sera considéré par l'ordonnanceur que beaucoup plus tard, lorsque le sémaphore d'attente d'événement sur entrée/sortie sera positionné à « faux » (et il peut y avoir plusieurs sémaphores à considérer simultanément.
- L'ordonnanceur doit obéir à des interruptions « temps réel » qu'il doit servir immédiatement (on parle, ici, du « vrai » temps réel, pas le niveau de priorité élévé appelé « temps réel » par abus de langage dans Microsoft Windows).
- L'ordonnanceur à un travail un peu plus compliqué avec les machines multiprocesseurs ou les processeurs multicœur (multicore). Il faut distribuer le travail entre plusieurs processeurs (le tourniquet tourne devant plusieurs processeurs) en optimisant cette distribution de manière à réduire l'overhead dû aux changements de contexte. En particulier, il y a les applications multiprocessus (elles exécutent plusieurs processus en parallèles dans plusieurs cœurs. L'ordonnanceur gère donc l'affinité.
Donc l'ordonnanceur ne ne contente pas de faire tourner le tourniquet. Il choisi les processus à exécuter, il choisi les processeurs (cœurs) à affecter aux processus, il gère les interruptions, il cherche à maintenir la perte de temps des commutations de contexte la plus basse possible en faisant des arbitrages. En plus, il n'y a pas que les cœurs réels, physiques, des processeurs multicœurs : l'ordonnanceur rencontre une difficulté particulière et supplémentaire avec les cœurs fictifs, virtuels, de l'hyperthreading.
Sur les machines de type PC les plus performantes, il n'y a, au maximum, que 8 cœurs, 4 réels et 4 fictifs. A l'instant où j'écris cet article, il y a 103 processus qui cherchent à s'exécuter avec les 8 cœurs de mon Intel I7. Il y a toujours beaucoup plus de processus que de processeurs. S'il y a plus de processeurs que de processus, il n'y a pas de commutations de contexte.
L'ordonnanceur est appelé scheduler en anglais.