# Fonctionnement d'un ordinateur/La tolérance aux pannes

Dans les chapitres précédents, nous avons supposé que les circuits font leur travail et ne commettent pas d'erreurs. Dans les faits, c'est une bonne approximation : il est rare qu'un circuit électronique dysfonctionne soudainement, sauf s'il est assez âgé et qu'il a commencé à se détériorer. Et même quand il y a une erreur, elle passe généralement inaperçue et l'ordinateur continue de fonctionner normalement. Cependant, cela ne signifie pas que les erreurs n'existent pas, et elles sont nombreuses.
Les erreurs en question se traduisent le plus souvent par l'inversion d'un bit : un bit censé être à 0 passe à 1, ou inversement. Pour donner un exemple, on peut citer l'incident du 18 mai 2003 dans la petite ville belge de Schaerbeek. Lors d'une élection, la machine à voter électronique enregistra un écart de 4096 voix entre le dépouillement traditionnel et le dépouillement électronique. La faute à un rayon cosmique, qui avait modifié l'état d'un bit de la mémoire de la machine à voter.
Mais qu'on se rassure : il existe des techniques pour détecter et corriger ces erreurs. Elles nécessitent toutes l'ajout de matériel, et ce sont ces circuits que nous allons voir ici. Elles sont peu utilisées dans les ordinateurs grand public, mais elles sont très importantes dans les domaines demandant des ordinateurs fiables, comme dans l'automobile, l'aviation, le spatial, l'industrie, etc. Et ce chapitre va expliquer ce qu'elles sont, et aussi comment les circuits élaborés permettent de s'en protéger.

## La cause des erreurs et défauts d'un circuit électronique

Les erreurs peuvent provenir d'un défaut électrique, d'un fil coupé, d'un transistor défaillant, ou tout autre raison qui cause une erreur permanente. Généralement, elles proviennent de l'usure d'un circuit électronique, de son vieillissement. Mais d'autres erreurs sont des erreurs temporaires provenant de phénomènes physiques externes au circuit. Il faut donc distinguer les erreurs permanentes des erreurs transitoires. Les premières perdurent après qu'elles apparaissent, ce sont des défauts permanents, qu'on ne peut pas corriger. Les secondes surviennent brutalement et cessent peu après leur apparition.

### Le vieillissement des circuits électroniques

Les circuits électroniques vieillissent. Les transistors vieillissent généralement assez bien, ce sont surtout les interconnexions métalliques entre transistors qui s'usent. La raison est que les interconnexions sont parcourues par des courants électriques assez forts, qui attaquent le métal. Quand un métal est parcourt par du courant, les électrons s'entrechoquent avec les atomes du métal, et ces derniers se déplacent progressivement : c'est le phénomène d'électro-migration. Des défauts apparaissent dans le métal : un atome manquant par-ci par-là, puis des défauts plan, des trous dans le métal, etc. Après un certain temps, ces défauts s'accumulent, au point que les interconnexions peuvent se couper en deux : le fil métallique est cassé.
L'électro-migration est d'autant plus forte que le courant est élevé, cela n'a rien d'étonnant. Mais le processus dépend aussi fortement de la température. En première approximation, la durée de vue d'un circuit électronique se calcule approximativement avec cette équation, appelée l'équation de Black :
    ${\text{durée de vie d'un circuit}}\propto {\frac {1}{I^{n}}}\times \exp {\left({\frac {A}{k_{B}T}}\right)}$
En clair, elle est d'autant plus faible que le courant est élevé, et que la température l'est aussi. La dépendance au courant est une loi de puissance, elle est donc plus faible que celle avec la température qui est exponentielle. Réduire la température de fonctionnement d'un ordinateur augmente donc drastiquement sa durée de vie. Et vu que plus un ordinateur est utilisé, plus il chauffe, cela explique pourquoi les ordinateurs beaucoup utilisés pour jouer à des jeux vidéos ne durent pas autant que ceux utilisés seulement pour de la bureautique.
Un autre facteur est la taille des interconnexions métalliques, en largeur. Plus un fil est épais, large, plus il sera difficile à couper à grand coup d'électro-migration. Et plus les processeurs se miniaturisent plus ces interconnexions sont petites, fines, faciles à casser. Autant cela ne posait pas de problème quand les interconnexions faisaient quelques centaines de micro-mètres, autant les interconnexions modernes de quelques microns se cassent rapidement.

### Les erreurs temporaires

D'autres erreurs sont cependant temporaires et ont des origines totalement différentes. La plupart proviennent de rayons cosmiques, de perturbations électromagnétiques, de radiations proches, peu importe. Les causes les plus communes sont les rayons cosmiques, des particules à haute énergie produites dans la haute atmosphère et qui traversent celle-ci à haute vitesse. Il arrive qu'elles soient interceptées par le semi-conducteur d'un transistor, ce qui le fait dysfonctionner temporairement. La seconde raison est celle des rayons alpha, provenant de la radioactivité naturelle qu'on trouve un peu partout. Et, ironie du sort, ces rayons alpha proviennent souvent du métal présent dans la puce elle-même !
La cause la plus commune est cependant la température. Plus un processeur ou une mémoire chauffe, moins ses transistors sont fiables. Les erreurs sont d'autant plus communes que la température est élevée. Et une autre raison est que la résistance des fils métalliques augmente avec la température : si un processeur chauffe trop, certains fils deviennent tellement résistifs qu'ils ne font plus passer le courant, ce qui fait que tout se passe comme si le fil était coupé ! C'est pour cela que les ordinateurs tendent à planter quand le processeur ou la mémoire chauffent trop, et vous en avez certainement déjà fait l'expérience. Les erreurs en question peuvent survenir à trois endroits différents : dans les circuits combinatoires, dans les mémoires et registres, lors de la transmission des données dans les interconnexions.

## Les circuits tolérants aux erreurs

Les erreurs peuvent survenir à des endroits très différents dans un ordinateur : dans le processeur, sa mémoire, dans un périphérique, dans le BIOS, etc. Dans ce qui va suivre, nous allons distinguer trois localisations : dans les circuits combinatoires, dans les mémoires et registres, dans les interconnexions entre circuits. Nous allons d'abord voir les techniques utilisées sur les circuits combinatoires, et nous prendrons l'exemple d'une unité de calcul pour simplifier les explications. Puis, nous allons voir ce qu'il en est pour les mémoires, registres, et bus de transmission. La raison est que les techniques utilisées pour les ALU et les mémoires/bus sont différentes en pratique, pour des raisons que nous expliquerons.
Pour les circuits combinatoires, les solutions sont diverses, mais on peut les classer en deux types : la redondance temporelle, et la redondance physique.
La redondance temporelle consiste à exécuter un calcul plusieurs fois, pour vérifier si le résultat est le même à chaque exécution. Typiquement, on exécute la même opération deux fois dans l'ALU, et on ne fait rien si les deux résultats sont identiques. Mais si les deux résultats sont différents, alors une erreur a eu lieu. Pour corriger l'erreur, l'idée est d'exécuter le calcul une troisième fois, voire plus, et de garder le résultat majoritaire.
La redondance physique, beaucoup plus simple, duplique le circuit et fait fonctionner les circuits dupliqués en parallèle, en leur envoyant les mêmes données au même moment. Les deux circuits sont censés fournir le même résultat si tout va bien. Mais en cas d'erreur de fonctionnement, les deux circuits fourniront un résultat différent, d'au moins un bit. Par exemple, on peut imaginer ce que cela donnerait avec des unités de calcul redondantes : toutes les unités de calcul recevraient les opérandes en même temps, feraient leurs calculs indépendamment les unes des autres, et fourniraient leur résultat à un système qui corrigerait d'éventuelles erreurs de calcul ou pannes.
Les deux solutions correspondent à des compromis différents. La redondance temporelle double ou triple les temps de calcul, mais ne duplique pas les circuits. À l'inverse, la redondance physique ne change pas beaucoup les temps de calcul, mais duplique les circuits et augmente le nombre de portes logiques/transistors utilisées. La redondance physique est plus utilisée que la redondance temporelle pour une raison simple : elle capture plus d'erreurs. Une erreur permanente, comme un circuit défectueux, est détectée par la redondance physique, mais pas par la redondance temporelle. La redondance temporelle ne détecte que les erreurs transitoires, celles liées à la température et/ou à des radiations.

### La détection d'erreur par comparaison de deux résultats

La méthode de détection d'erreur la plus simple consiste à effectuer un calcul deux fois, et à vérifier que les deux opérations donnent le même résultat. Si les deux exécutions du calcul donnent le même résultat, alors on considère qu'il n'y a pas eu d'erreurs. Par contre, si les deux résultats sont différents, alors on sait qu'une erreur a eu lieu. Par contre, une fois l'erreur détectée, on ne peut pas la corriger. Pour connaitre le bon résultat, on est obligé de refaire les calculs, ou d'utiliser d'autres méthodes pour corriger l'erreur.
Pour faire les deux calculs, on peut utiliser la redondance temporelle ou la redondance physique. La méthode la plus simple est la redondance physique, qui se contente de dupliquer le circuit, et d'ajouter un comparateur qui vérifie si les deux circuits donnent le même résultat. Le premier processeur à utiliser cette méthode était l'EDVAC, dans les années 1950. Il comprenait deux unités de calcul, et continuait d’exécuter son programme tant que les deux unités de calcul donnaient des résultats identiques. En cas de non-agrément entre les deux unités de calcul, le processeur ré-exécutait l'instruction fautive.
Il faut noter que les deux unités de calcul ne sont pas forcément identiques. Un cas classique est celui des circuits multiplieurs : le multiplieur redondant ne fournit par le résultat complet, mais un résultat partiel. Prenons la multiplication A * B = C, la même multiplication mais modulo N fonctionnera aussi : (A mod N) * (B mod N) = (C mod N). L'idée est donc que le second multiplieur fait le calcul modulo N, N choisit de manière à réduire fortement le cout en circuits. Évidemment, cette solution n'est pas aussi puissante que simplement dupliquer le multiplieur : un calcul erroné peut coller parfaitement au résultat mod N adéquat du second multiplieur. Plus N est petit, plus la chance que cela arrive est forte.
Une autre solution utilise la redondance temporelle. Le calcul est fait deux fois de suite par la même ALU, on met en attente les deux résultats dans deux registres, et on les compare. Là encore, il y a un coût en circuits : il faut ajouter un comparateur et des registres. Elle n'est pas très utilisée, car son compromis en circuits et en performance ne vaut pas le coup. On double le temps de calcul, mais le coût en circuits n'est pas négligeable. On ajoute une seconde ALU d'un côté, deux registres de l'autre, le cout en circuits est significatif dans les deux solutions.
Une version améliorée de la redondance temporelle permet de détecter une erreur permanente. L'idée est que l'on exécute le calcul avec les opérandes normaux, puis le même calcul avec les mêmes opérandes décalées de quelques rangs. Le résultat des deux opérations devrait être identique, si ce n'est que le second est décalé de quelques rangs. Dans ce cas, il est possible que les deux résultats ne concordent pas, ce qui permet de détecter une erreur. Cela fonctionne car une erreur permanente fausse un bit précis du résultat, un bit d'un poids bien précis. En décalant les opérandes, on peut capter l'erreur, car elle n'est pas au même endroit entre les deux calculs.

### La correction d'erreur avec redondance physique

Après avoir vu comment détecter es erreurs, passons maintenant à la correction des erreurs. Pour corriger une erreur, il faut cependant aller plus loin que simplement doubler les circuits ou exécuter un calcul deux fois. Il faut le faire trois fois ! En clair, avoir trois copies d'un même circuit, ou exécuter un calcul trois fois. L'idée est que l'on dispose de trois résultats. S'ils sont identiques, on considère qu'il n'y a pas eu d'erreurs, le cas où les trois résultats sont erronés sont très rares. Mais si ce n'est pas le cas, alors une erreur a survenu, peut-être deux. Dans ce cas, on suppose que sur les trois résultats, l'erreur est le résultat qui diffère des deux autres. L'idée est que si une erreur a lieu, elle ne touche généralement qu'un seul circuit, le cas où deux circuits sont touchés par une erreur simultanée étant assez rare.
La méthode se généralise à plus de trois composants, il faut juste que le nombre soit impair. Par exemple, prenons le cas avec 5 circuits. Si un circuit tombe en panne, les quatre autres donneront un résultat correct. Avec 4 sorties contre une, c'est le résultat correct qui l'emportera. Tant que plus de la moitié des composants n'a pas de panne, le vote à majorité donne systématiquement le bon résultat. Par exemple, utiliser 5 composants permet de résister à une panne de 2 composants, en utiliser 7 permet de résister à 3 composants en panne, etc.
En clair, on choisit le résultat majoritaire. D'où le fait que la méthode s'appelle le vote à majorité. Reste à voir comment l'implémenter avec un circuit électronique. L'idée est simplement que les circuits dupliqués sont suivis par un circuit de correction d'erreur, qui choisit le résultat majoritaire. On peut aussi avoir d'autres circuits, mais ce n'est pas systématique.
La solution la plus simple ne choisit pas la valeur majoritaire, mais applique le vote à majorité au niveau des bits. Pour le dire autrement, le vote à majorité s’effectue alors sur des bits de même poids, de la même colonne, comme illustré ci-dessous. Par exemple, si deux bits sont à 1 et le dernier à 0, alors le bit majoritaire est à 1.
En clair, pour chaque colonne, on regarde les bits de même poids, et on détermine quel est le bit majoritaire. Il existe des portes logiques spécifiquement conçues pour faire ce calcul, les portes à majorité. Nous avions vu de telles portes il y a quelques chapitres, nous ne reviendrons pas dessus. Nous allons juste montrer le circuit équivalent à une telle porte, pour 3 entrées :
On voit que le circuit de vote à majorité est donc très simple ! Il suffit de rajouter deux couches de portes logiques en sortie des circuits dupliqués. Le cout en circuit et en performance est donc très bas ! Pas inexistant, d'où son absence dans les processeurs grand public, mais très faible. C'est pour cela que cette méthode est presque toujours utilisée au lieu de l'usage d'un multiplexeur. Un autre avantage est qu'il n'y a pas besoin de circuit pour détecter l'erreur : elle est corrigée automatiquement par le circuit de vote à majorité, sans vraiment qu'il y ait détection de l'erreur en tant que telle.

## Les architectures parallèles tolérantes aux pannes

Les architectures tolérantes aux pannes sont des ordinateurs dont le but est la fiabilité, la résistance aux pannes, la tolérance aux erreurs. Elles peuvent continuer de fonctionner même avec un ou plusieurs composants en panne. Elles sont surtout utilisées dans des milieux comme l'aéronautique, les satellites, ou dans tout système dit critique, où des vies peuvent être en jeu. Elles utilisent des circuits tolérants aux erreurs, mais aussi d'autres techniques purement architecturales.
La tolérance aux pannes nécessite d'implémenter plusieurs techniques. La principale est l'usage de code correcteurs d'erreur, qui sont notamment utilisés au niveau de la mémoire et des dispositifs de stockage. Pour simplifier, les architectures tolérantes aux pannes utilisent généralement des mémoires RAM de type ECC, éventuellement des technologies RAID pour le disque dur et les SSDs. Les architectures les plus simples se contentent de cela, car la majorité des erreurs proviennent de la mémoire, pas du processeur.
Un technique complémentaire revient à dupliquer du matériel en plusieurs exemplaires. Ainsi, si un exemplaire tombe en panne, les autres pourront prendre la relève. Le cout en circuit peut être acceptable pour des applications importantes, comme dans le spatial, l'aviation, l'automobile, etc. Un exemple de redondance souvent utilisé dans les serveurs est la technologie RAID utilisée sur les disques durs, qui consiste à dupliquer les disques durs, à placer les mêmes données sur différents disques durs au cas où l'un d'entre eux tombe en panne. Notons que la technologie RAID combine codes ECC et duplication de disques durs.

### Les architectures parallèles tolérantes aux pannes

Vous l'avez vu venir, mais certaines architectures tolérantes aux pannes dupliquent le processeur et exécutent le même programme dessus. Si les deux programmes fournissent le même résultat, tout va bien. Mais quand les deux fournissent des résultats différents, on doit alors utiliser un mécanisme de correction, par exemple utiliser un vote à majorité. La technique s'adapte aussi très bien sur les architectures multicœurs. Par exemple, les processeurs multicœurs actuels disposent de plusieurs cœurs, qui sont physiquement identiques, sauf dans quelques cas spécifiques. Aussi, il est possible d’exécuter un même programme en plusieurs exemplaires, plusieurs instances : un par cœur.
Généralement, les processeurs/cœurs exécutent tous le même programme en même temps, en parallèle les uns des autres. Ils effectuent la même opération en même temps, aux mêmes cycles d'horloge, ils sont parfaitement synchronisés. Ainsi, si un processeur tombe en panne, les autres peuvent continuer le travail immédiatement. Un tel système est appelé un système lockstep. De tels systèmes permettent de détecter les erreurs de fonctionnement et éventuellement de les corriger.
Une autre possibilité est que les différents processeurs exécutent le même programme, avec les mêmes données, mais sans garanties de synchronisation fixe. Ainsi, quand un processeur plante ou a une erreur, les autres peuvent reprendre la suite, avec cependant un léger décalage.
Il arrive aussi que ce ne soit pas le cas, et qu'un seul processeur fonctionne, pendant que les autres servent de réserve activable en cas de panne, ce qui fait qu'il ne s'agit pas vraiment d'une architecture parallèle. Ils sont parfois couplés avec des systèmes comme une sauvegarde périodique du programme en cours d’exécution. Mais concentrons-nous sur le cas où les processeurs fonctionnent en parallèle.
La mémoire peut être dupliquée ou non. Il est en théorie possible d'utiliser plusieurs processeurs combinés avec une mémoire unique, qui est alors une mémoire ECC. On se retrouve alors avec un système à mémoire partagée, de type MISD. À l'opposé, il est possible d'avoir autant de processeurs que de mémoires, ce qui correspond à une architecture distribuée où tous les processeurs exécutent le même programme. Ces deux choix sont des cas extrêmes et il est possible d'imaginer des cas où le nombre de processeur et de mémoire est différent, avec un système d'interconnexion complexe entre processeur et mémoire.

### Les systèmes lockstep : double et triple modular redundancy

Dans ce qui suit, nous allons étudier les systèmes lockstep, conceptuellement plus simples que les autres. Nous allons étudier comment on détecte et corrige les erreurs sur un tel système. Ici, nous allons supposer que l'on a 2, 3, 4 processeurs, auxquels nous allons ajouter un circuit qui se charge de détecter si un processeur a fait une erreur, et de la corriger si besoin. Appelons-le le circuit d'interface ECC.
Pour illustrer le tout, imaginons que les processeurs soient connectés à une mémoire ECC unique. Le circuit d'interface ECC est alors situé entre la mémoire et le processeur, éventuellement entre le CPU et les entrées-sorties. Les lectures et écritures de chaque processeur sont simultanées, car on suppose les CPU identiques et qu'ils exécutent le même programme. Dans ce cas, le circuit d'interface ECC reçoit les données et adresses de tous les processeurs, et ils vérifient si tous les résultats sont identiques. Si ce n'est pas le cas, il y a une erreur et il faut la corriger, ou du moins faire quelque chose.

#### La double modular redundancy

Les systèmes lockstep les plus simples n'utilisent que deux processeurs. On peut détecter une erreur en comparant la sortie des deux processeurs : si elle est différente, on est certain qu'il y a eu une erreur (on suppose qu'il n'y en a pas eu en cas d'accord entre les deux processeurs). Une fois l'erreur détectée, on ne peut cependant pas la corriger.
Il est cependant possible de corriger des erreurs en ajoutant encore de la redondance. Le système précédent, à deux processeurs, est dupliqué en deux exemplaires minimum, parfois plus. Chaque exemplaire est appelé une unité dans ce qui suit. L'idée est que si on détecte une erreur dans une unité, on n'utilise pas le résultat invalide qu'elle fournit. À la place, on prend le résultat fournit par une autre unité dont le résultat est valide. Pour faire ce choix, on utilise un simple multiplexeur ou un switch. La configuration du multiplexeur se fait en utilisant les bits de sortie des comparateurs, qui sont combinés à travers un encodeur.
Un exemple typique est l'architecture Stratus (aussi connue IBM/System 88). Celui-ci contient quatre processeurs logiques qui font leurs calculs en parallèle : le résultat est choisi parmi les processeurs sans pannes. Une panne ou erreur est détectée avec duplication par comparaison : chaque processeur logique est dupliqué et une panne est détectée si les deux processeurs sont en désaccord sur le résultat. L'ensemble contient donc huit processeurs.

#### La triple modular redundancy et le vote à majorité

Le double modular redundancy ne permet que de détecter les erreurs dans le cas le plus simple, et a un cout en circuits très important dans les versions améliorées où des unités sont dupliquées. Mais il existe une méthode beaucoup plus simple qui d'avoir une capacité de correction d'erreur importante, tout en ayant un cout en circuit assez faible. Il s'agit de la triple modular redundancy et de ses améliorations.
La méthode la plus simple utilise trois processeurs. L'idée est de prendre le résultat majoritaire parmi les trois résultats fournit. Si les trois résultats sont identiques, on considère qu'il n'y a pas d'erreur vu que la possibilité d'une triple erreur est très rare. Mais si les résultats sont différents, on suppose que le résultat invalide est celui qui diffère des deux autres, car la probabilité d'une double erreur est plus rare que celle d'une erreur unique. Pour cela, on ajoute un circuit de vote à majorité en sortie des trois processeurs. Le circuit en question a été vu il y a quelques chapitres, dans le chapitre sur les circuits correcteurs d'erreur, c'est un circuit bit à bit, qui agit sur des bits individuels.
    La méthode du vote à majorité peut s'adapter à plus de 3 processeurs. Par exemple, si on a 7 processeurs, et que 5 d'entre eux fournissent le même résultat, alors ce résultat est valide et c'est les deux autres qui ont de bonnes chances d'être faux.
Le vote à majorité peut s'utiliser pour les communications avec la mémoire : le circuit reçoit les adresses et données de chaque processeur, fait un vote à majorité, et envoie le résultat à la RAM. Le vote à majorité a été utilisé sur pas mal de mainframes anciens, où les processeurs étaient dupliqués et les entrées-sorties des processeurs étaient combinés par un vote à majorité.
Le circuit de vote à majorité est un point faillible du système : s'il tombe en panne, tout le système tombe en panne. Pour éviter cela, il est là possible de dupliquer le système de vote à majorité. Mais cela n'a d'utilité que dans des cas précis. Par exemple, c'est très utile si la mémoire est dupliquée, si le système contient plusieurs mémoires. Dans ce cas, chaque mémoire est associée à un circuit de vote à majorité qui lui est propre.
Il faut noter que les processeurs utilisés pour le vote à majorité ne sont pas forcément identiques ! Bien sûr, tout est plus simple s'ils sont identiques et qu'ils exécutent exactement le même programme, le même code binaire. Mais il est possible d'utiliser des processeurs différents. Par exemple, le Boeing 777 disposait, dans ses circuits de contrôle, d'un système de ce genre. Il contenait trois unités, chaque unité contenant trois processeurs : un Intel 80486, Un Motorola 68040 et un AMD 29050. Les résultats calculés par les trois processeurs étaient envoyés à un système de vote à majorité qui vérifiait que les trois processeurs fournissaient le même résultat.
Faire ainsi permet de se protéger des erreurs de conception du processeur. En effet, tous les processeurs commerciaux possèdent des bugs, des défauts de conception, qui se manifestent souvent dans des conditions très précises et qui sont souvent sans conséquences. Mais dans des domaines où des vies sont en jeu, on ne peut pas faire comme si ces bugs n'existaient pas et on doit trouver un moyen de s'en protéger au mieux. D'où le fait d'utiliser des processeurs différents, dont les bugs seront différents. Si un calcul est erroné à cause d'un bug, cela ne touchera qu'un processeur sur les trois, pas les autres, vu qu'ils n'auront pas exactement le même bug.

## La redondance temporelle sur les processeurs multithréadés

Il est aussi possible d'utiliser de la redondance sur des architectures multihtreadées, sauf que cette fois-ci, le programme originel et sa copie redondante s’exécutent sur le même cœur, simplement pas exactement en même temps. Techniquement, elles s’exécutent plus ou moins simultanément vu de l’extérieur, mais pas si on regarde au niveau des cycles d'horloge. Tel cycle sera attribué à un programme, le cycle suivant à sa copie, etc. Il s'agit d'un type de redondance appelée la redondance temporelle, où les calculs/instructions sont effectués plusieurs fois par le même circuit. Elle permet de détecter les erreurs temporaires qui surviennent une fois, donc impactent une exécution du calcul, mais pas les suivantes ou précédentes.
Précisons que le programme originel a la priorité sur le programme redondant. Il prend donc de l'avance et termine ses instructions avant sa copie redondante. Les mécanismes pour comparer les programme original et redondant sont donc plus compliqués que prévu. Il faut mettre en attente les résultats du programme originel, généralement en conservant une copie du banc de registres quelque part, et la comparer avec l'état équivalent calculé par le programme redondant. Rien que déterminer l'état redondant est assez complexe, et demande de gérer l'historique d’exécution des deux programmes.
Un autre défaut est que l'interaction avec la mémoire complique l'implémentation. Un point important est que les deux programmes, l'original et le redondant, doivent avoir le même espace d'adressage. Ou du moins, leur mémoire virtuelle et table des pages doit être configurée de manière à ce que les deux programmes lisent et écrivent au même endroit pour une même instruction. Le protocole de cohérence des caches doit tenir compte de la présence d'un programme redondant pour éviter de nombreuses invalidations de cache, et son adaptation n'est pas triviale. Une autre solution est d'utiliser deux mémoires séparées, mais elle n'est pas triviale, surtout que dans ce cas, autant utiliser plusieurs processeurs séparés.