c++ visual Kompilieren einer Anwendung zur Verwendung in Umgebungen mit hoher Radioaktivität




vs 2017 c++ project (19)

Angesichts der Kommentare von supercat, der Tendenzen moderner Compiler und anderer Dinge wäre ich versucht, in die alten Zeiten zurückzukehren und den gesamten Code in Assembler- und statischen Speicherzuordnungen zu schreiben. Für diese Art der Zuverlässigkeit, denke ich, entstehen bei der Montage keine großen prozentualen Kostenunterschiede mehr.

Wir kompilieren eine eingebettete C / C ++ - Anwendung, die in einem abgeschirmten Gerät in einer mit ionisierender Strahlung bombardierten Umgebung eingesetzt wird. Wir verwenden GCC und Cross-Compiling für ARM. Bei der Bereitstellung generiert unsere Anwendung einige fehlerhafte Daten und stürzt häufiger ab, als wir möchten. Die Hardware wurde für diese Umgebung entwickelt und unsere Anwendung läuft seit mehreren Jahren auf dieser Plattform.

Gibt es Änderungen an unserem Code oder Verbesserungen bei der Kompilierung, die vorgenommen werden können, um Softwarefehler und Speicherbeschädigungen zu identifizieren / korrigieren, die durch einzelne Ereignisstörungen verursacht werden? Haben es andere Entwickler geschafft, die schädlichen Auswirkungen von Softwarefehlern auf eine lang laufende Anwendung zu reduzieren?


Einen Punkt scheint niemand erwähnt zu haben. Sie sagen, Sie entwickeln sich in GCC und kompilieren auf ARM. Woher wissen Sie, dass Sie keinen Code haben, der Annahmen über den freien Arbeitsspeicher, die Ganzzahlgröße, die Zeigergröße, die Dauer einer bestimmten Operation, die ununterbrochene Laufzeit des Systems oder ähnliches enthält? Dies ist ein sehr häufiges Problem.

Die Antwort ist normalerweise ein automatisierter Unit-Test. Schreiben Sie Testgeschirre, die den Code auf dem Entwicklungssystem ausführen, und führen Sie dann dieselben Testgeschirre auf dem Zielsystem aus. Achten Sie auf Unterschiede!

Überprüfen Sie auch Ihr eingebettetes Gerät auf Errata. Möglicherweise gibt es etwas zu "Tun Sie dies nicht, weil es abstürzt, aktivieren Sie also diese Compiler-Option, und der Compiler wird es umgehen".

Kurz gesagt, die wahrscheinlichste Ursache für Abstürze sind Fehler in Ihrem Code. Machen Sie sich (noch) keine Gedanken über esoterischere Fehlermodi, bis Sie sich verflucht sicher sind, dass dies nicht der Fall ist.


Hier sind eine Menge Antworten, aber ich werde versuchen, meine Ideen dazu zusammenzufassen.

Etwas stürzt ab oder funktioniert nicht richtig. Dies kann auf Ihre eigenen Fehler zurückzuführen sein. Es sollte dann leicht zu beheben sein, wenn Sie das Problem gefunden haben. Aber es gibt auch die Möglichkeit von Hardwarefehlern - und das ist schwierig, wenn nicht unmöglich, insgesamt zu beheben.

Ich würde empfehlen, zuerst zu versuchen, die problematische Situation durch Protokollierung (Stapel, Register, Funktionsaufrufe) zu erfassen - entweder durch Protokollierung in einer Datei oder durch direkte Übertragung ("oh nein - ich bin abgestürzt").

Die Wiederherstellung nach einer solchen Fehlersituation erfolgt entweder durch einen Neustart (wenn die Software noch aktiv ist) oder durch ein Zurücksetzen der Hardware (z. B. Hardware-Watchdogs). Einfacher von vorne zu beginnen.

Wenn das Problem hardwarebezogen ist, können Sie anhand der Protokollierung ermitteln, bei welchem ​​Funktionsaufrufproblem ein Insiderwissen darüber vorliegt, was wo nicht funktioniert.

Auch wenn Code relativ komplex ist - es ist sinnvoll, ihn zu "teilen und zu erobern" - was bedeutet, dass Sie einige Funktionsaufrufe entfernen / deaktivieren, bei denen Sie vermuten, dass es sich um ein Problem handelt. Die Entscheidung "funktioniert nicht", nach der Sie sich auf eine andere Codehälfte konzentrieren können. (Wo ist das Problem)

Tritt das Problem nach einiger Zeit auf - dann kann ein Stapelüberlauf vermutet werden -, ist es besser, Stapelpunktregister zu überwachen - wenn sie ständig wachsen.

Und wenn Sie es schaffen, Ihren Code vollständig zu minimieren, bis eine Anwendung der Art "Hallo Welt" - und die immer noch zufällig ausfällt -, werden Hardwareprobleme erwartet - und es muss ein "Hardware-Upgrade" durchgeführt werden - was bedeutet, dass Sie eine solche CPU / RAM / ... -Hardware-Kombination, die Strahlung besser verträgt.

Das Wichtigste ist wahrscheinlich, wie Sie Ihre Protokolle zurückerhalten, wenn die Maschine vollständig gestoppt ist / zurückgesetzt wurde / nicht funktioniert - wahrscheinlich das erste, was Bootstap tun sollte -, wenn sich eine problematische Situation abzeichnet.

Wenn es in Ihrer Umgebung auch möglich ist, ein Signal zu senden und eine Antwort zu empfangen, können Sie versuchen, eine Art Online-Remote-Debugging-Umgebung zu erstellen. Dann müssen jedoch mindestens Kommunikationsmedien und ein Prozessor / ein RAM im Betriebszustand sein. Und mit Remote-Debugging meine ich entweder einen GDB / GDB-Stub-Ansatz oder Ihre eigene Implementierung dessen, was Sie benötigen, um von Ihrer Anwendung zurückzugelangen (z. B. Protokolldateien herunterladen, Aufrufliste herunterladen, RAM herunterladen, Neustart).


Da Sie speziell nach Softwarelösungen fragen und C ++ verwenden, können Sie mithilfe der Operatorüberladung Ihre eigenen, sicheren Datentypen erstellen. Zum Beispiel:

Anstelle der Verwendung uint32_t (und double , int64_t usw.), machen sie ihre eigenen , SAFE_uint32_t die ein Vielfaches (mindestens 3) von uint32_t enthält. Überladen Sie alle Operationen, die Sie ausführen möchten (* + - / << >> = ==! = Etc), und führen Sie die überladenen Operationen unabhängig für jeden internen Wert aus, dh führen Sie sie nicht einmal aus und kopieren Sie das Ergebnis. Überprüfen Sie vorher und nachher, ob alle internen Werte übereinstimmen. Stimmen die Werte nicht überein, können Sie den falschen Wert auf den am häufigsten verwendeten Wert aktualisieren. Wenn kein häufig verwendeter Wert vorhanden ist, können Sie sicher mitteilen, dass ein Fehler vorliegt.

Auf diese Weise spielt es keine Rolle, ob in der ALU, in den Registern, im RAM oder auf einem Bus eine Beschädigung auftritt, Sie haben immer noch mehrere Versuche und eine sehr gute Chance, Fehler abzufangen. Beachten Sie jedoch, dass dies nur für die Variablen funktioniert, die Sie ersetzen können - Ihr Stapelzeiger ist beispielsweise weiterhin anfällig.

Eine Nebengeschichte: Ich bin auf ein ähnliches Problem gestoßen, auch auf einen alten ARM-Chip. Es stellte sich heraus, dass es sich um eine Toolchain handelte, die eine alte Version von GCC verwendete, die zusammen mit dem von uns verwendeten speziellen Chip in bestimmten Edge-Fällen einen Fehler auslöste, der (manchmal) die Übergabe von Werten an Funktionen beschädigte. Stellen Sie sicher, dass Ihr Gerät keine Probleme hat, bevor Sie es für Radioaktivität verantwortlich machen, und ja, manchmal handelt es sich um einen Compiler-Fehler =)


Haftungsausschluss: Ich bin kein Experte für Radioaktivität und arbeite auch nicht für diese Art von Anwendung. Aber ich habe an weichen Fehlern und Redundanz für die Langzeitarchivierung kritischer Daten gearbeitet, die in gewisser Weise miteinander verknüpft sind (dasselbe Problem, unterschiedliche Ziele).

Das Hauptproblem bei Radioaktivität ist meiner Meinung nach, dass Radioaktivität Bits umschalten kann, so dass Radioaktivität jeden digitalen Speicher manipulieren kann / wird . Diese Fehler werden normalerweise als weiche Fehler , Bit-Rot usw. bezeichnet.

Die Frage ist dann: Wie kann man zuverlässig rechnen, wenn der Speicher unzuverlässig ist?

Um die Häufigkeit von Softwarefehlern erheblich zu reduzieren (auf Kosten des Rechenaufwands, da es sich meist um softwarebasierte Lösungen handelt), können Sie entweder:

  • Verlassen Sie sich auf das gute alte Redundanzschema und insbesondere auf die effizienteren Fehlerkorrekturcodes (gleicher Zweck, aber cleverere Algorithmen, damit Sie mehr Bits mit weniger Redundanz wiederherstellen können). Dies wird manchmal (fälschlicherweise) auch als Prüfsumme bezeichnet. Bei dieser Art von Lösung müssen Sie den vollständigen Status Ihres Programms jederzeit in einer Hauptvariablen / -klasse (oder einer Struktur?) Speichern, einen ECC berechnen und prüfen, ob der ECC korrekt ist, bevor Sie etwas unternehmen nicht reparieren Sie die Felder. Diese Lösung garantiert jedoch nicht, dass Ihre Software funktioniert (einfach, dass sie ordnungsgemäß funktioniert, wenn dies möglich ist, oder wenn dies nicht möglich ist, funktioniert sie nicht mehr, da ECC Ihnen mitteilen kann, wenn etwas nicht stimmt. In diesem Fall können Sie Ihre Software stoppen, damit Sie keine falschen Ergebnisse erhalten).

  • oder Sie können ausfallsichere algorithmische Datenstrukturen verwenden , die bis zu einem gewissen Grad garantieren, dass Ihr Programm auch bei weichen Fehlern korrekte Ergebnisse liefert. Diese Algorithmen können als Mischung gängiger algorithmischer Strukturen mit eingebauten ECC-Schemata angesehen werden. Dies ist jedoch weitaus widerstandsfähiger, da das Ausfallsicherheitsschema eng an die Struktur gebunden ist, sodass Sie keine zusätzlichen Prozeduren codieren müssen ECC zu überprüfen, und in der Regel sind sie viel schneller. Diese Strukturen bieten eine Möglichkeit, um sicherzustellen, dass Ihr Programm unter allen Bedingungen bis zur theoretischen Grenze von weichen Fehlern funktioniert. Sie können diese ausfallsicheren Strukturen auch mit dem Redundanz- / ECC-Schema für zusätzliche Sicherheit mischen (oder Ihre wichtigsten Datenstrukturen als ausfallsichere Daten codieren, und den Rest der aus den Hauptdatenstrukturen neu zu berechnenden Daten,als normale Datenstrukturen mit etwas ECC oder einer sehr schnell zu berechnenden Paritätsprüfung).

Wenn Sie an stabilen Datenstrukturen interessiert sind (ein neues, aber aufregendes Feld in der Algorithmus- und Redundanzentwicklung), empfehle ich Ihnen, die folgenden Dokumente zu lesen:

  • Resilient Algorithmen Datenstrukturen Intro von Giuseppe F.Italiano, Universität Rom "Tor Vergata"

  • Christiano, P., Demaine, ED & Kishore, S. (2011). Verlustfreie fehlertolerante Datenstrukturen mit additivem Overhead. In Algorithmen und Datenstrukturen (S. 243-254). Springer Berlin Heidelberg.

  • Ferraro-Petrillo, U., Grandoni, F. & amp; Italiano, GF (2013). Gegen Speicherfehler resistente Datenstrukturen: eine experimentelle Untersuchung von Wörterbüchern. Journal of Experimental Algorithmics (JEA), 18, 1-6.

  • Italiano, GF (2010). Ausfallsichere Algorithmen und Datenstrukturen. In Algorithmen und Komplexität (S. 13-24). Springer Berlin Heidelberg.

Wenn Sie mehr über das Gebiet der belastbaren Datenstrukturen erfahren möchten , können Sie die Arbeiten von Giuseppe F. Italiano (und sich durch die Referenzen arbeiten) und das Faulty-RAM-Modell (eingeführt in Finocchi et al. 2005; Finocchi und Italiano 2008).

/ EDIT: Ich habe das Verhindern / Wiederherstellen von Softfehlern hauptsächlich für RAM-Speicher und Datenspeicher veranschaulicht, aber ich habe nicht über Rechenfehler (CPU) gesprochen . In anderen Antworten wurde bereits auf die Verwendung atomarer Transaktionen wie in Datenbanken hingewiesen, daher werde ich ein anderes, einfacheres Schema vorschlagen: Redundanz und Mehrheitsentscheidung .

Die Idee ist, dass Sie einfach x-mal die gleiche Berechnung für jede Berechnung durchführen, die Sie durchführen müssen, und das Ergebnis in x verschiedenen Variablen speichern (mit x> = 3). Sie können dann Ihre x Variablen vergleichen :

  • Wenn alle übereinstimmen, liegt überhaupt kein Rechenfehler vor.
  • Wenn sie nicht übereinstimmen, können Sie mit der Mehrheit abstimmen, um den richtigen Wert zu erhalten. Da dies bedeutet, dass die Berechnung teilweise fehlerhaft war, können Sie auch einen System- / Programmstatus-Scan auslösen, um zu überprüfen, ob der Rest in Ordnung ist.
  • Wenn die Mehrheitsentscheidung keinen Gewinner ermitteln kann (alle x-Werte sind unterschiedlich), ist dies ein perfektes Signal für Sie, um die Ausfallsicherungsprozedur auszulösen (Neustart, Alarmierung des Benutzers usw.).

Dieses Redundanzschema ist im Vergleich zu ECC (praktisch 0 (1)) sehr schnell und gibt Ihnen ein klares Signal, wenn Sie ausfallsicher sein müssen . Es ist auch (fast) garantiert, dass die Mehrheitsentscheidung niemals fehlerhafte Ausgaben erzeugt und sich auch von geringfügigen Rechenfehlern erholt , da die Wahrscheinlichkeit, dass x Berechnungen die gleiche Ausgabe liefern, unendlich gering ist (da es eine große Menge möglicher Ausgaben gibt, ist dies nahezu unmöglich zufällig dreimal das Gleiche bekommen, noch weniger Chancen, wenn x> 3).

Mit der Mehrheitswahl sind Sie also vor fehlerhafter Ausgabe sicher, und mit Redundanz x == 3 können Sie 1 Fehler beheben (mit x == 4 können 2 Fehler behoben werden usw. - die genaue Gleichung lautet, nb_error_recoverable == (x-2) wo x die Zahl ist von Berechnungswiederholungen, da Sie mindestens 2 übereinstimmende Berechnungen benötigen, um mit der Mehrheit der abgegebenen Stimmen wiederherzustellen).

Der Nachteil ist, dass Sie x-mal statt einmal berechnen müssen, sodass Sie zusätzliche Berechnungskosten haben, die lineare Komplexität jedoch asymptotisch ist und Sie nicht viel für die Vorteile verlieren, die Sie gewinnen. Eine schnelle Möglichkeit, eine Mehrheitsabstimmung durchzuführen, besteht darin, den Modus in einem Array zu berechnen. Sie können jedoch auch einen Medianfilter verwenden.

Wenn Sie außerdem sicherstellen möchten, dass die Berechnungen korrekt durchgeführt werden, und wenn Sie Ihre eigene Hardware herstellen können, können Sie Ihr Gerät mit x CPUs aufbauen und das System so verkabeln, dass die Berechnungen automatisch mit der Mehrheit der abgegebenen Stimmen auf den x CPUs dupliziert werden mechanisch am Ende (zum Beispiel mit UND / ODER-Toren). Dies wird häufig in Flugzeugen und geschäftskritischen Geräten implementiert (siehe dreifache modulare Redundanz ). Auf diese Weise haben Sie keinen Rechenaufwand (da die zusätzlichen Berechnungen parallel ausgeführt werden), und Sie haben eine weitere Schutzschicht vor weichen Fehlern (da die Berechnungsduplizierung und die Mehrheitsabstimmung direkt von der Hardware und nicht von verwaltet werden Software - die leichter beschädigt werden kann, da ein Programm einfach aus Bits besteht, die im Speicher gespeichert sind ...).


Was Ihnen helfen könnte, ist ein watchdog . Wachhunde wurden in den 1980er Jahren in großem Umfang in der industriellen Datenverarbeitung eingesetzt. Hardware-Ausfälle waren dann viel häufiger - eine andere Antwort bezieht sich auch auf diesen Zeitraum.

Ein Watchdog ist eine kombinierte Hardware- / Softwarefunktion. Die Hardware ist ein einfacher Zähler, der von einer Zahl (z. B. 1023) auf Null herunterzählt. TTL oder eine andere Logik könnte verwendet werden.

Die Software wurde so konzipiert, dass eine Routine den korrekten Betrieb aller wichtigen Systeme überwacht. Wenn diese Routine korrekt ausgeführt wird = Der Computer läuft einwandfrei, wird der Zähler auf 1023 zurückgesetzt.

Der Gesamtaufbau ist so, dass die Software unter normalen Umständen verhindert, dass der Hardwarezähler Null erreicht. Wenn der Zähler Null erreicht, führt die Hardware des Zählers seine Einzeltask aus und setzt das gesamte System zurück. Aus der Perspektive eines Zählers ist Null gleich 1024 und der Zähler zählt weiter zurück.

Dieser Watchdog stellt sicher, dass der angeschlossene Computer in vielen, vielen Fällen von Fehlern neu gestartet wird. Ich muss zugeben, dass ich mit Hardware, die eine solche Funktion auf heutigen Computern ausführen kann, nicht vertraut bin. Schnittstellen zu externer Hardware sind heute wesentlich komplexer als früher.

Ein inhärenter Nachteil des Watchdogs besteht darin, dass das System vom Zeitpunkt des Ausfalls an nicht verfügbar ist, bis der Watchdog-Zähler Null + Neustartzeit erreicht. Während diese Zeit im Allgemeinen viel kürzer ist als jede externe oder menschliche Intervention, muss das unterstützte Gerät in diesem Zeitraum ohne Computersteuerung weiterarbeiten können.


Erstens gestalten Sie Ihre Anwendung um Versagen . Stellen Sie sicher, dass im Rahmen des normalen Durchflussbetriebs ein Zurücksetzen erwartet wird (abhängig von Ihrer Anwendung und der Art des Ausfalls, weich oder hart). Dies ist schwer zu erreichen: Kritische Vorgänge, die ein gewisses Maß an Transaktionalität erfordern, müssen möglicherweise auf Assembly-Ebene überprüft und optimiert werden, damit eine Unterbrechung an einem wichtigen Punkt nicht zu inkonsistenten externen Befehlen führt. Fallen Sie schnell aus, sobald eine nicht behebbare Speicherbeschädigung oder eine Abweichung des Steuerflusses erkannt wird. Wenn möglich, Fehler protokollieren.

Zweitens, wenn möglich, Korruption korrigieren und weitermachen . Dies bedeutet, dass konstante Tabellen (und, wenn möglich, Programmcode) häufig überprüft und korrigiert werden müssen. Vielleicht vor jeder Hauptoperation oder bei einem zeitgesteuerten Interrupt und Speichern von Variablen in Strukturen, die automatisch korrigiert werden (wieder vor jeder Hauptoperation oder bei einem zeitgesteuerten Interrupt eine Mehrheitsabstimmung von 3 durchführen und korrigieren, ob es sich um eine einzelne Abweichung handelt). Nach Möglichkeit Korrekturen protokollieren.

Drittens Testfehler . Richten Sie eine wiederholbare Testumgebung ein, die Bits im Speicher pseudozufällig spiegelt. Auf diese Weise können Sie Korruptionssituationen replizieren und Ihre Anwendung entsprechend gestalten.


Verwenden Sie einen zyklischen Scheduler . Auf diese Weise können Sie regelmäßige Wartungszeiten hinzufügen, um die Richtigkeit kritischer Daten zu überprüfen. Das am häufigsten auftretende Problem ist die Beschädigung des Stapels. Wenn Ihre Software zyklisch ist, können Sie den Stack zwischen den Zyklen neu initialisieren. Verwenden Sie die Stapel nicht für Interrupt-Aufrufe, sondern richten Sie für jeden wichtigen Interrupt-Aufruf einen separaten Stapel ein.

Ähnlich wie beim Watchdog-Konzept handelt es sich um Deadline-Timer. Starten Sie einen Hardware-Timer, bevor Sie eine Funktion aufrufen. Wenn die Funktion nicht vor Ablauf des Deadline-Timers zurückkehrt, laden Sie den Stack neu und versuchen Sie es erneut. Wenn es nach 3/5 Versuchen immer noch fehlschlägt, müssen Sie das ROM neu laden.

Teilen Sie Ihre Software in Teile auf und isolieren Sie diese Teile, um separate Speicherbereiche und Ausführungszeiten zu verwenden (insbesondere in einer Steuerungsumgebung). Beispiel: Signalerfassung, Vorbesitzdaten, Hauptalgorithmus und Ergebnisumsetzung / -übertragung. Dies bedeutet, dass ein Fehler in einem Teil keine Fehler im Rest des Programms verursacht. Während wir also die Signalerfassung reparieren, werden die restlichen Aufgaben mit veralteten Daten fortgesetzt.

Alles braucht CRCs. Wenn Sie nicht genügend RAM haben, benötigt auch Ihre .text-Datei eine CRC. Überprüfen Sie die CRCs regelmäßig, wenn Sie einen zyklischen Scheduler verwenden. Einige Compiler (nicht GCC) können CRCs für jeden Abschnitt generieren, und einige Prozessoren haben dedizierte Hardware, um CRC-Berechnungen durchzuführen. Durch das Überprüfen der CRCs wird der ECC-Controller im Speicher außerdem aufgefordert, Einzelbitfehler zu reparieren, bevor ein Problem auftritt.


Vielleicht wäre es hilfreich zu wissen, ob die Hardware "für diese Umgebung ausgelegt" ist. Wie wird das Vorhandensein von SEU-Fehlern korrigiert und / oder angezeigt?

Bei einem mit Weltraumforschung zusammenhängenden Projekt hatten wir eine benutzerdefinierte MCU, die bei SEU-Fehlern eine Ausnahme / Unterbrechung auslöste, jedoch mit einer gewissen Verzögerung, dh einige Zyklen könnten nach derjenigen ausgeführt werden, die die SEU-Ausnahme verursachte.

Besonders anfällig war der Datencache, sodass ein Handler die fehlerhafte Cache-Zeile ungültig machte und das Programm neu startete. Nur, dass aufgrund der Ungenauigkeit der Ausnahme die Abfolge der Insns, die von der Ausnahme ausgelöst werden, möglicherweise nicht neu gestartet werden kann.

Wir haben die gefährlichen (nicht neustartbaren) Sequenzen identifiziert (wie z. B. lw $3, 0x0($2) gefolgt von einem Insn, das modifiziert $2 und nicht datenabhängig ist $3 ), und ich habe Änderungen an GCC vorgenommen, sodass solche Sequenzen nicht auftreten (z. B. als letzte Möglichkeit, die Sequenzen zu trennen) zwei insns von a nop ).

Nur etwas zu beachten ...


Die NASA hat ein Papier über strahlungshärtende Software. Es beschreibt drei Hauptaufgaben:

  1. Regelmäßige Überwachung des Speichers auf Fehler und anschließende Beseitigung dieser Fehler
  2. robuste Fehlerbehebungsmechanismen und
  3. die Fähigkeit, neu zu konfigurieren, wenn etwas nicht mehr funktioniert.

Beachten Sie, dass die Speicher-Scan-Rate so häufig sein sollte, dass Mehrbitfehler selten auftreten, da die meisten ECC Speicher von Einzelbitfehlern und nicht von Mehrbitfehlern wiederhergestellt werden können.

Die Wiederherstellung nach robusten Fehlern umfasst die Übertragung des Steuerungsflusses (normalerweise ein Neustart eines Prozesses zu einem Zeitpunkt vor dem Fehler), die Freigabe von Ressourcen und die Wiederherstellung von Daten.

Ihre Hauptempfehlung für die Datenwiederherstellung besteht darin, die Notwendigkeit zu vermeiden, indem Zwischendaten als temporär behandelt werden, sodass ein Neustart vor dem Fehler auch die Daten in einen zuverlässigen Zustand zurückversetzt. Dies klingt ähnlich wie das Konzept von "Transaktionen" in Datenbanken.

Sie diskutieren Techniken, die besonders für objektorientierte Sprachen wie C ++ geeignet sind. Zum Beispiel

  1. Softwarebasierte ECCs für zusammenhängende Speicherobjekte
  2. Programmieren nach Vertrag : Überprüfen der Vor- und Nachbedingungen und anschließende Überprüfung des Objekts, um sicherzustellen, dass es sich noch in einem gültigen Zustand befindet.

Und zufällig hat die NASA C ++ für Großprojekte wie den Mars Rover verwendet .

Die Abstraktion und Kapselung von C ++ - Klassen ermöglichte eine schnelle Entwicklung und Prüfung zwischen mehreren Projekten und Entwicklern.

Sie haben bestimmte C ++ - Funktionen vermieden, die Probleme verursachen könnten:

  1. Ausnahmen
  2. Vorlagen
  3. Iostream (keine Konsole)
  4. Mehrfachvererbung
  5. Überladung des Operators (außer new und delete )
  6. Dynamische Zuordnung (Verwendung eines dedizierten Speicherpools und Platzierung new , um die Möglichkeit einer Beschädigung des System-Heapspeichers zu vermeiden).

Wenn Ihre Hardware ausfällt, können Sie sie mithilfe eines mechanischen Speichers wiederherstellen. Wenn Ihre Codebasis klein ist und über physischen Speicherplatz verfügt, können Sie einen mechanischen Datenspeicher verwenden.

Es wird eine Materialoberfläche geben, die nicht durch Strahlung beeinträchtigt wird. Mehrere Gänge werden da sein. Ein mechanischer Leser läuft auf allen Zahnrädern und kann flexibel auf und ab bewegt werden. Down bedeutet, dass es 0 ist und up bedeutet, dass es 1 ist. Aus 0 und 1 können Sie Ihre Codebasis generieren.


Ich arbeite seit ca. 4-5 Jahren mit Software- / Firmware-Entwicklung und Umgebungstests von miniaturisierten Satelliten * und möchte hier meine Erfahrungen teilen.

* ( miniaturisierte Satelliten sind aufgrund ihrer relativ kleinen, begrenzten Größe für elektronische Komponenten viel anfälliger für Störungen bei einzelnen Ereignissen als größere Satelliten )

Um sehr präzise und direkt zu sein: Es gibt keinen Mechanismus, mit dem die Software / Firmware selbst eine erkennbare, fehlerhafte Situation beheben kann, ohne mindestens eine Kopie der Mindestarbeitsversion der Software / Firmware für Wiederherstellungszwecke - und mit Unterstützung der Hardware die Erholung (funktional).

Diese Situation wird nun normalerweise sowohl auf Hardware- als auch auf Software-Ebene behandelt. Auf Wunsch teile ich hier mit, was wir auf Software-Ebene tun können.

  1. Wiederherstellungszweck . Bieten Sie die Möglichkeit, Ihre Software / Firmware in der realen Umgebung zu aktualisieren / neu zu kompilieren / neu zu flashen. Dies ist ein Muss für jede Software / Firmware in einer stark ionisierten Umgebung. Ohne dies könnten Sie redundante Software / Hardware haben, so viele Sie möchten, aber an einem Punkt werden sie alle in die Luft jagen. Bereiten Sie diese Funktion vor!

  2. ... minimale Arbeitsversion ... Reagierende, mehrfache Kopien, minimale Version der Software / Firmware in Ihrem Code. Dies entspricht dem abgesicherten Modus in Windows. Verwenden Sie nicht nur eine voll funktionsfähige Version Ihrer Software, sondern mehrere Kopien der Mindestversion Ihrer Software / Firmware. Die minimale Kopie hat normalerweise eine viel geringere Größe als die vollständige Kopie und hat fast immer nur die folgenden zwei oder drei Merkmale:

    1. in der Lage, Befehle von einem externen System abzuhören,
    2. in der Lage, die aktuelle Software / Firmware zu aktualisieren,
    3. in der Lage, die Haushaltsdaten der Grundoperation zu überwachen.
  3. ... irgendwo kopieren ... ... irgendwo redundante Software / Firmware haben.

    1. Sie können mit oder ohne redundante Hardware versuchen, redundante Software / Firmware in Ihrem ARM uC zu haben. Dies geschieht normalerweise, indem zwei oder mehr identische Software / Firmware in separaten Adressen vorhanden sind, die sich gegenseitig einen Herzschlag senden - es ist jedoch immer nur eine aktiv. Wenn bekannt ist, dass eine oder mehrere Software / Firmware-Komponenten nicht reagieren, wechseln Sie zu der anderen Software / Firmware. Der Vorteil dieses Ansatzes ist, dass wir sofort nach Auftreten eines Fehlers einen Funktionsersatz erhalten können - ohne Kontakt mit einem externen System / einer externen Partei, die für die Erkennung und Behebung des Fehlers verantwortlich ist (im Satellitenfall ist dies in der Regel das Mission Control Center). MCC)).

      Streng genommen besteht der Nachteil ohne redundante Hardware darin, dass Sie nicht alle einzelnen Fehlerquellen beseitigen können . Zumindest haben Sie immer noch einen einzigen Fehlerpunkt, nämlich den Schalter selbst (oder häufig den Anfang des Codes). Für ein Gerät mit begrenzter Größe in einer stark ionisierten Umgebung (z. B. Pico / Femto-Satelliten) ist es dennoch erwägenswert, den einzelnen Fehlerpunkt ohne zusätzliche Hardware auf einen Punkt zu reduzieren. Irgendwann wäre der Code für das Umschalten sicherlich viel geringer als der Code für das gesamte Programm - was das Risiko eines einzelnen Ereignisses erheblich verringert.

    2. Wenn Sie dies nicht tun, sollten Sie mindestens eine Kopie in Ihrem externen System haben, die mit dem Gerät in Kontakt kommen und die Software / Firmware aktualisieren kann (im Satellitenfall ist dies wiederum das Missionskontrollzentrum).

    3. Sie können die Kopie auch in Ihrem permanenten Speicher Ihres Geräts haben, der ausgelöst werden kann, um die Software / Firmware des laufenden Systems wiederherzustellen
  4. ... feststellbare fehlerhafte Situation. Der Fehler muss feststellbar sein , normalerweise durch die Hardware- Fehlerkorrektur- / Erkennungsschaltung oder durch ein kleines Stück Code zur Fehlerkorrektur / -erkennung. Es ist am besten, solchen Code klein, mehrfach und unabhängig von der Hauptsoftware / Firmware zu platzieren. Ihre Hauptaufgabe ist nur das Prüfen / Korrigieren. Wenn die Hardwareschaltung / Firmware zuverlässig ist (z. B. strahlungsgehärteter als die Reste - oder mehrere Schaltungen / Logiken aufweist), können Sie eine Fehlerkorrektur in Betracht ziehen. Wenn dies nicht der Fall ist, ist es besser, die Fehlererkennung zu verwenden. Die Korrektur kann durch ein externes System / Gerät erfolgen. Für die Fehlerkorrektur können Sie einen grundlegenden Fehlerkorrekturalgorithmus wie Hamming / Golay23 verwenden, da diese sowohl in der Schaltung als auch in der Software einfacher implementiert werden können. Letztendlich hängt es jedoch von den Fähigkeiten Ihres Teams ab. Zur Fehlererkennung wird normalerweise CRC verwendet.

  5. ... Hardware, die die Wiederherstellung unterstützt Nun kommt der schwierigste Aspekt zu diesem Thema. Letztendlich erfordert die Wiederherstellung, dass die Hardware, die für die Wiederherstellung verantwortlich ist, mindestens funktionsfähig ist. Wenn die Hardware dauerhaft defekt ist (normalerweise nach Erreichen einer bestimmten Ionisierungsdosis ), kann die Software (leider) nicht zur Wiederherstellung beitragen. Aus diesem Grund ist Hardware zu Recht das Hauptanliegen eines Geräts, das einer hohen Strahlung ausgesetzt ist (z. B. Satellit).

Zusätzlich zu dem oben genannten Vorschlag, einen Firmware-Fehler aufgrund eines einzelnen Ereignisses zu antizipieren, möchte ich Ihnen Folgendes vorschlagen:

  1. Fehlererkennungs- und / oder Fehlerkorrekturalgorithmus im Kommunikationsprotokoll zwischen Subsystemen. Dies ist ein weiteres Muss, um unvollständige / falsche Signale zu vermeiden, die von einem anderen System empfangen werden

  2. Filtern Sie in Ihrem ADC-Messwert. Verwenden Sie den ADC-Messwert nicht direkt. Filtern Sie es nach Medianfilter, Mittelwertfilter oder anderen Filtern - vertrauen Sie niemals einem einzelnen Messwert. Probieren Sie mehr, nicht weniger - vernünftigerweise.


Was Sie fragen, ist ein ziemlich komplexes Thema - nicht leicht zu beantworten. Andere Antworten sind in Ordnung, aber sie deckten nur einen kleinen Teil aller Dinge ab, die Sie tun müssen.

Wie in den Kommentaren zu sehen ist , ist es nicht möglich, Hardwareprobleme zu 100% zu beheben, jedoch ist es mit hoher Wahrscheinlichkeit möglich, sie mit verschiedenen Techniken zu reduzieren oder zu beheben.

Wenn ich Sie wäre, würde ich die Software mit der höchsten Sicherheitsstufe (SIL-4) erstellen . Holen Sie sich das IEC 61513-Dokument (für die Nuklearindustrie) und befolgen Sie es.


Mit C können möglicherweise Programme geschrieben werden, die sich in solchen Umgebungen robust verhalten, jedoch nur, wenn die meisten Formen der Compileroptimierung deaktiviert sind. Die Optimierung von Compilern wurde entwickelt, um viele scheinbar redundante Codierungsmuster durch "effizientere" zu ersetzen, und hat möglicherweise keine Ahnung, warum der Programmierer x==42 testet, wenn der Compiler weiß, dass x keine Möglichkeit hat, etwas anderes zu halten, weil Der Programmierer möchte verhindern, dass bestimmter Code ausgeführt wird, wenn x einen anderen Wert enthält - auch in Fällen, in denen dieser Wert nur dann gespeichert werden kann, wenn das System eine Art elektrischen Fehler empfängt.

Das Deklarieren von Variablen als volatile ist oft hilfreich, aber möglicherweise kein Allheilmittel. Beachten Sie von besonderer Bedeutung, dass für die sichere Codierung häufig gefährliche Vorgänge mit Hardware-Verriegelungen verbunden sind, deren Aktivierung mehrere Schritte erfordert, und dass der Code nach folgendem Muster geschrieben wird:

... code that checks system state
if (system_state_favors_activation)
{
  prepare_for_activation();
  ... code that checks system state again
  if (system_state_is_valid)
  {
    if (system_state_favors_activation)
      trigger_activation();
  }
  else
    perform_safety_shutdown_and_restart();
}
cancel_preparations();

Wenn ein Compiler den Code relativ wörtlich übersetzt und alle Überprüfungen des Systemzustands nach prepare_for_activation() wiederholt werden, ist das System möglicherweise robust gegenüber nahezu jedem plausiblen einzelnen Glitch-Ereignis, auch gegenüber solchen, die den Programmzähler und willkürlich prepare_for_activation() würden Stapel. Wenn ein prepare_for_activation() unmittelbar nach einem Aufruf von prepare_for_activation() , würde dies bedeuten, dass die Aktivierung angemessen gewesen wäre (da es keinen anderen Grund gibt, warum prepare_for_activation() vor dem prepare_for_activation() aufgerufen worden wäre). Wenn der Fehler dazu führt, dass der Code nicht prepare_for_activation() auf prepare_for_activation() , es jedoch keine nachfolgenden Fehlerereignisse gibt, kann der Code nicht auf trigger_activation() ohne zuvor die Validierungsprüfung durchlaufen oder cancel_preparations aufgerufen zu haben [wenn der Stapel fehlerhaft funktioniert, Die Ausführung kann unmittelbar vor trigger_activation() nachdem der Kontext, der prepare_for_activation() aufgerufen prepare_for_activation() , zurückgekehrt ist. Der Aufruf von cancel_preparations() wäre jedoch zwischen den Aufrufen von prepare_for_activation() und trigger_activation() , wodurch der letztere Aufruf harmlos wird.

Ein solcher Code kann in traditionellem C sicher sein, aber nicht in modernen C-Compilern. Solche Compiler können in dieser Art von Umgebung sehr gefährlich sein, da sie aggressiv nur Code enthalten möchten, der in Situationen relevant ist, die über einen genau definierten Mechanismus zustande kommen könnten und dessen sich daraus ergebende Konsequenzen ebenfalls genau definiert wären. Code, dessen Zweck darin besteht, Fehler zu erkennen und zu beseitigen, kann in einigen Fällen die Situation verschlimmern. Wenn der Compiler feststellt, dass die versuchte Wiederherstellung in einigen Fällen undefiniertes Verhalten hervorruft, kann daraus geschlossen werden, dass die Bedingungen, die in solchen Fällen eine Wiederherstellung erforderlich machen würden, möglicherweise nicht eintreten können, wodurch der Code beseitigt wird, der sie überprüft hätte.


Dies ist ein äußerst umfangreiches Thema. Grundsätzlich können Sie sich nicht wirklich von einer Speicherbeschädigung erholen, aber Sie können zumindest versuchen, umgehend einen Fehler zu verursachen . Hier sind einige Techniken, die Sie verwenden könnten:

  • Prüfsummen-Konstantendaten . Wenn Sie Konfigurationsdaten haben, die für lange Zeit konstant bleiben (einschließlich der von Ihnen konfigurierten Hardwareregister), berechnen Sie die Prüfsumme bei der Initialisierung und überprüfen Sie diese regelmäßig. Wenn Sie eine Nichtübereinstimmung feststellen, müssen Sie diese neu initialisieren oder zurücksetzen.

  • Variablen redundant speichern . Wenn Sie eine wichtige Variable x , schreiben Sie deren Wert in x1 , x2 und x3 und lesen Sie sie als (x1 == x2) ? x2 : x3 (x1 == x2) ? x2 : x3 .

  • Programmablaufüberwachung implementieren. XOR ein globales Flag mit einem eindeutigen Wert in wichtigen Funktionen / Zweigen, die von der Hauptschleife aufgerufen werden. Wenn Sie das Programm in einer strahlungsfreien Umgebung mit einer Testabdeckung von nahezu 100% ausführen, sollten Sie am Ende des Zyklus die Liste der zulässigen Werte des Flags erhalten. Bei Abweichungen zurücksetzen.

  • Überwachen Sie den Stapelzeiger . Vergleichen Sie zu Beginn der Hauptschleife den Stapelzeiger mit seinem erwarteten Wert. Bei Abweichung zurücksetzen.


In dieser Antwort wird davon ausgegangen, dass Sie ein System benötigen, das ordnungsgemäß funktioniert, und darüber hinaus ein System, das nur minimale Kosten verursacht oder schnell ist. Die meisten Leute, die mit radioaktiven Dingen spielen, legen Wert auf Korrektheit / Sicherheit gegenüber Geschwindigkeit / Kosten

Einige Leute haben Hardware-Änderungen vorgeschlagen, die Sie vornehmen können (in Ordnung - es gibt hier bereits viele gute Antworten, und ich habe nicht die Absicht, alles zu wiederholen), und andere haben Redundanz vorgeschlagen (im Prinzip großartig), aber ich glaube nicht Jeder hat vorgeschlagen, wie diese Redundanz in der Praxis funktionieren könnte. Wie scheitern Sie? Woher weißt du, wenn etwas schief gelaufen ist? Viele Technologien arbeiten auf der Basis, dass alles funktionieren wird, und daher ist es schwierig, mit Fehlern umzugehen. Einige verteilte Computertechnologien, die für die Skalierung ausgelegt sind, erwarten jedoch einen Ausfall (schließlich ist bei ausreichender Skalierung ein Ausfall eines Knotens von vielen bei jeder MTBF für einen einzelnen Knoten unvermeidbar). Sie können dies für Ihre Umgebung nutzen.

Hier sind ein paar Ideen:

  • Stellen Sie sicher, dass Ihre gesamte Hardware n mal repliziert wird (wobei n größer als 2 und vorzugsweise ungerade ist) und dass jedes Hardwareelement mit jedem anderen Hardwareelement kommunizieren kann. Ethernet ist ein naheliegender Weg, aber es gibt viele andere, weitaus einfachere Wege, die einen besseren Schutz bieten (z. B. CAN). Minimieren Sie gemeinsame Komponenten (auch Netzteile). Dies kann beispielsweise das Abtasten von ADC-Eingängen an mehreren Stellen bedeuten.

  • Stellen Sie sicher, dass sich Ihr Anwendungsstatus an einem einzigen Ort befindet, z. B. in einer Zustandsmaschine. Dies kann vollständig auf RAM basieren, schließt jedoch eine stabile Speicherung nicht aus. Es wird also an mehreren Orten aufbewahrt.

  • Verabschiedung eines Quorum-Protokolls für Zustandsänderungen. Siehe RAFT zum Beispiel. Da Sie in C ++ arbeiten, gibt es dafür bekannte Bibliotheken. Änderungen am FSM würden nur vorgenommen, wenn die Mehrheit der Knoten zustimmt. Verwenden Sie eine als funktionierend bekannte Bibliothek für den Protokollstapel und das Quorumprotokoll, anstatt selbst eine zu erstellen. Andernfalls wird Ihre gesamte Arbeit an der Redundanz verschwendet, wenn das Quorumprotokoll auflegt.

  • Stellen Sie sicher, dass Sie Ihre FSM mit einer Prüfsumme (z. B. CRC / SHA) versehen und die CRC / SHA in der FSM selbst speichern (sowie in der Nachricht senden und die Nachrichten selbst mit einer Prüfsumme versehen). Fordern Sie die Knoten auf, ihren FSM regelmäßig anhand dieser Prüfsumme zu überprüfen, eingehende Nachrichten zu prüfen und zu überprüfen, ob ihre Prüfsumme mit der Prüfsumme des Quorums übereinstimmt.

  • Bauen Sie so viele interne Überprüfungen wie möglich in Ihr System ein, sodass Knoten, die ihren eigenen Fehler feststellen, neu gestartet werden (dies ist besser, als die Hälfte der Arbeit fortzusetzen, vorausgesetzt, Sie haben genügend Knoten). Versuchen Sie, sie beim Neustart sauber aus dem Quorum entfernen zu lassen, falls sie nicht wieder auftauchen. Lassen Sie sie beim Neustart das Software-Image (und alles andere, was sie laden) überprüfen und einen vollständigen RAM-Test durchführen, bevor sie sich wieder dem Quorum unterziehen.

  • Verwenden Sie Hardware, um Sie zu unterstützen, aber tun Sie dies vorsichtig. Sie können beispielsweise ECC-RAM abrufen und regelmäßig lesen / schreiben, um ECC-Fehler zu korrigieren (und in Panik zu geraten, wenn der Fehler nicht korrigierbar ist). (Aus dem Speicher) statischer RAM ist jedoch weitaus toleranter gegenüber ionisierender Strahlung als DRAM. Daher ist es möglicherweise besser, stattdessen statischen DRAM zu verwenden. Siehe auch den ersten Punkt unter "Dinge, die ich nicht tun würde".

Nehmen wir an, Sie haben innerhalb eines Tages eine 1% ige Ausfallwahrscheinlichkeit für einen bestimmten Knoten und tun so, als könnten Sie Fehler völlig unabhängig machen. Bei 5 Knoten müssen drei innerhalb eines Tages ausfallen, was einer Wahrscheinlichkeit von 0,00001% entspricht. Mit more kommt man auf die Idee.

Dinge, die ich nicht tun würde:

  • Unterschätzen Sie den Wert, nicht das Problem zu haben, mit dem Sie anfangen sollen. Wenn das Gewicht keine Rolle spielt, wird ein großer Metallblock um Ihr Gerät eine weitaus billigere und zuverlässigere Lösung sein, als es sich ein Team von Programmierern vorstellen kann. Das Gleiche gilt für die optische Kopplung von EMI-Eingängen usw. Versuchen Sie auf jeden Fall, bei der Beschaffung Ihrer Komponenten die Komponenten zu verwenden, die gegen ionisierende Strahlung am besten geeignet sind.

  • Rollen Sie Ihre eigenen Algorithmen . Leute haben das schon mal gemacht. Nutzen Sie ihre Arbeit. Fehlertoleranz und verteilte Algorithmen sind schwierig. Verwenden Sie die Arbeit anderer Leute, wo immer dies möglich ist.

  • Verwenden Sie komplizierte Compilereinstellungen in der naiven Hoffnung, dass Sie weitere Fehler entdecken. Wenn Sie Glück haben, können Sie weitere Fehler entdecken. Wahrscheinlicher ist, dass Sie einen Codepfad innerhalb des Compilers verwenden, der weniger getestet wurde, insbesondere wenn Sie ihn selbst gerollt haben.

  • Verwenden Sie Techniken, die in Ihrer Umgebung nicht getestet wurden. Die meisten Leute, die Hochverfügbarkeitssoftware schreiben, müssen Fehlermodi simulieren, um zu überprüfen, ob ihre HA korrekt funktioniert, und verpassen daher viele Fehlermodi. Sie sind in der glücklichen Lage, häufige Ausfälle auf Abruf zu haben. Testen Sie also jede Technik und stellen Sie sicher, dass ihre Anwendung die MTBF tatsächlich um einen Betrag verbessert, der die Komplexität bei der Einführung übersteigt (bei Komplexität treten Fehler auf). Wenden Sie dies insbesondere auf meine Ratschläge zu Quorum-Algorithmen usw. an.


Vielleicht interessieren Sie sich auch für die umfangreiche Literatur zum Thema algorithmische Fehlertoleranz. Dies schließt die alte Zuweisung ein: Schreiben Sie eine Sortierung, die ihre Eingabe korrekt sortiert, wenn eine konstante Anzahl von Vergleichen fehlschlägt (oder die etwas schlechtere Version, wenn die asymptotische Anzahl fehlgeschlagener Vergleiche als log(n) für n Vergleiche skaliert).

Ein Ort, an dem Sie mit dem Lesen beginnen können, ist Huangs und Abrahams Artikel " Algorithmusbasierte Fehlertoleranz für Matrixoperationen " aus dem Jahr 1984. Ihre Idee ähnelt in etwa der homomorphen verschlüsselten Berechnung (sie ist jedoch nicht wirklich dieselbe, da sie versuchen, Fehler auf Betriebsebene zu erkennen / zu korrigieren).

Ein jüngerer Nachkomme dieser Arbeit ist Bosilca, Delmas, Dongarra und Langous " Algorithmusbasierte Fehlertoleranz für Hochleistungsrechnen ".


Hier sind einige Gedanken und Ideen:

Verwenden Sie ROM kreativer.

Speichern Sie alles, was Sie können, im ROM. Speichern Sie die Nachschlagetabellen im ROM, anstatt sie zu berechnen. (Stellen Sie sicher, dass Ihr Compiler Ihre Nachschlagetabellen in den Nur-Lese-Bereich ausgibt. Drucken Sie die Speicheradressen zur Laufzeit aus, um dies zu überprüfen.) Speichern Sie Ihre Interrupt-Vektortabelle im ROM. Führen Sie natürlich einige Tests durch, um festzustellen, wie zuverlässig Ihr ROM mit Ihrem RAM verglichen wird.

Verwenden Sie Ihren besten RAM für den Stapel.

SEUs im Stack sind wahrscheinlich die wahrscheinlichste Absturzquelle, da dort normalerweise Indexvariablen, Statusvariablen, Rückgabeadressen und Zeiger verschiedener Art vorkommen.

Implementieren Sie Timer-Tick- und Watchdog-Timer-Routinen.

Sie können bei jedem Zeitgeber-Tick eine Routine zur Überprüfung der Systemintegrität sowie eine Watchdog-Routine ausführen, um die Systemblockierung zu handhaben. Ihr Hauptcode kann auch in regelmäßigen Abständen einen Zähler erhöhen, um den Fortschritt anzuzeigen, und die Routine zur Überprüfung der Integrität kann sicherstellen, dass dies geschehen ist.

Implementieren Sie error-correcting-codes in der Software.

Sie können Ihren Daten Redundanz hinzufügen, um Fehler zu erkennen und / oder zu korrigieren. Dadurch wird die Verarbeitungszeit verlängert und der Prozessor möglicherweise für längere Zeit der Strahlung ausgesetzt, wodurch sich die Wahrscheinlichkeit von Fehlern erhöht. Daher müssen Sie den Kompromiss in Betracht ziehen.

Erinnere dich an die Caches.

Überprüfen Sie die Größe Ihrer CPU-Caches. Daten, auf die Sie in letzter Zeit zugegriffen oder die Sie geändert haben, befinden sich wahrscheinlich in einem Cache. Ich glaube, Sie können zumindest einige der Caches deaktivieren (mit einem hohen Leistungsaufwand). Sie sollten dies versuchen, um zu sehen, wie anfällig die Caches für SEUs sind. Wenn die Caches härter als der Arbeitsspeicher sind, können Sie wichtige Daten regelmäßig lesen und erneut schreiben, um sicherzustellen, dass sie im Cache bleiben und den Arbeitsspeicher wieder in Einklang bringen.

Verwenden Sie Seitenfehlerbehandlungsroutinen geschickt.

Wenn Sie eine Speicherseite als nicht vorhanden markieren, gibt die CPU einen Seitenfehler aus, wenn Sie versuchen, darauf zuzugreifen. Sie können einen Seitenfehler-Handler erstellen, der einige Überprüfungen durchführt, bevor die Leseanforderung bearbeitet wird. (PC-Betriebssysteme verwenden dies, um Seiten, die auf die Festplatte ausgelagert wurden, transparent zu laden.)

Verwenden Sie die Assembler-Sprache für wichtige Dinge (die alles sein können).

Mit der Assemblersprache wissen Sie , was sich in den Registern und im RAM befindet. Sie wissen, welche speziellen RAM-Tabellen die CPU verwendet, und Sie können Dinge auf Umwegen entwerfen, um Ihr Risiko gering zu halten.

Verwenden Sie objdump , um sich die generierte Assemblersprache anzusehen und herauszufinden, wie viel Code jede Ihrer Routinen in Anspruch nimmt.

Wenn Sie ein großes Betriebssystem wie Linux verwenden, fragen Sie nach Problemen. Es gibt einfach so viel Komplexität und so viele Dinge, die schief gehen.

Denken Sie daran, es ist ein Spiel der Wahrscheinlichkeiten.

Ein Kommentator sagte

Jede Routine, die Sie zum Abfangen von Fehlern schreiben, kann aus derselben Ursache fehlschlagen.

Während dies zutrifft, ist die Wahrscheinlichkeit von Fehlern in den (sagen wir) 100 Byte Code und Daten, die erforderlich sind, damit eine Prüfroutine richtig funktioniert, viel geringer als die Wahrscheinlichkeit von Fehlern an anderer Stelle. Wenn Ihr ROM ziemlich zuverlässig ist und fast alle Codes / Daten tatsächlich im ROM sind, sind Ihre Chancen sogar noch besser.

Verwenden Sie redundante Hardware.

Verwenden Sie mindestens zwei identische Hardware-Setups mit identischem Code. Bei abweichenden Ergebnissen sollte ein Reset ausgelöst werden. Bei 3 oder mehr Geräten können Sie mithilfe eines "Abstimmungssystems" versuchen, zu identifizieren, welches Gerät kompromittiert wurde.


Wie wäre es, wenn Sie viele Instanzen Ihrer Anwendung ausführen würden? Wenn Abstürze auf zufällige Speicherbitänderungen zurückzuführen sind, besteht die Möglichkeit, dass einige Ihrer App-Instanzen es schaffen und genaue Ergebnisse liefern. Es ist wahrscheinlich ziemlich einfach (für jemanden mit statistischem Hintergrund), zu berechnen, wie viele Instanzen Sie bei gegebener Bit-Flop-Wahrscheinlichkeit benötigen, um einen so kleinen Gesamtfehler zu erzielen, wie Sie möchten.







fault-tolerance