Le rôle d'un ordonnanceur temps réel est de vérifier la faisabilité du système.
Il garantit que l'arrivée d'une nouvelle tâche, acceptée par l'ordonnanceur, sera ordonnançable.
\subsection{Priorités}
Les ordonnanceurs peuvent être à priorité fixe (chaque tâche conserve sa priorité durant toute sa durée de vie), ou à priorité dynamique (la priorité d'une tâche peut changer pendant son exécution).
Les ordonnanceurs à priorité fixe sont plus répandus.
Les priorités peuvent être déterminées selon~: l'échéance relative (D~: durée), la période (T~: échéance) ou l'importance de la tâche (P).
On peut alors avoir~:
\begin{itemize}
\item Rate Monotonic (RM) ---
La tâche ayant la plus petite période est la plus prioritaire.
\item Deadline Monotonic (DM) ---
La tâche ayant la plus petite échéance relative est la plus prioritaire.
\item Highest Priority First (HPF) ---
Les priorités sont attribuées aux tâches selon leur importance.
\item La tâche peut changer de priorité à chacune de ses activations, selon un des paramètres variables suivants~:
\begin{itemize}
\item D (échéance absolue)
\item T (période)
\item C (temps d'exécution restant)
\end{itemize}
\item Earliest Deadline First (EDF) ---
La tâche la plus proche de son échéance absolue aura la priorité la plus élevé.
C'est l'ordonnanceur le plus optimal.
\item Least Laxity First (LLF) ---
La tâche la plus prioritaire est celle de moindre laxité (différence entre l'échéance absolue et l'instant de terminaison de la tâche si on l'exécute totalement).
Avec l'exemple du Earliest Deadline First (EDF)~: la priorité change à chaque activation, on n'obtient donc pas forcément le pire temps de réponse dès la première activation.
Il faut donc un calcul de temps de réponse sur plusieurs activations.
L'ensemble $A$ représentant tous les instants d'activation dans la période active, le calcul du pire temps de réponse d'une tâche nécessite d'examiner plusieurs dates d'activation $a \in A$.
On dit qu'un ordonnanceur est optimal lorsqu'il trouve une solution d'ordonnancement à chaque fois que cette solution existe.
Lorsqu'il ne trouve pas de solution d'ordonnancement, alors aucun autre algorithme d'ordonnancement ne sera capable d'en trouver une.
\begin{itemize}
\item RM --- préemptif, $D_i = T_i$
\item DM --- préemptif, $D_i \leq T_i$
\item LLF --- préemptif
\item EDF --- toujours
\end{itemize}
\subsection{Synchronisation}
On cherche à éliminer les accès concurrents.
Cela s'appelle l'\emph{exclusion mutuelle}.
Toutes les instructions manipulant une ou plusieurs ressources critiques forment une section critique.
La protection se fait par verrou~: sémaphores, mutex, ou variables conditionnelles.
\subsection{Inversion de priorité}
Une tâche de haute priorité peut se bloquer sur une section critique par une tâche moins prioritaire.
Cela laisse le temps à une autre tâches moins prioritaire d'être exécuté avant.
\subsection{Interblocage}
Quand deux tâches ont besoin d'accéder simultanément à deux ressources partagées, elles se bloquent mutuellement.
\subsection{Héritage de priorité}
Le protocole d'héritage de priorité (Priority Inheritance Protocol, PIP) vise à éviter les blocages.
Si une tâche de basse priorité détient le verrou sur une ressource demandée par une tâche plus prioritaire, il faut élever la priorité de la première tâche au niveau de la tâche prioritaire jusqu'à ce qu'elle libère la ressource.