2008-10-08 11 views
8

Ich untersuche die Grundprinzipien des Speicherns des Status eines ausführenden Programms auf der Festplatte und das erneute Einspielen. In dem aktuellen Design, das wir haben, wird jedes Objekt (welches ein C-Level-Ding mit Funktionszeigerlisten ist, eine Art von Low-Level-home-made-Objektorientierung - und es gibt sehr gute Gründe, dies auf diese Weise zu tun) aufgerufen, um den expliziten Status in ein beschreibbares und wiederherstellbares Format zu exportieren. Die Schlüsseleigenschaft, um dies zum Laufen zu bringen, besteht darin, dass alle zu einem Objekt gehörenden Zustände tatsächlich in den Objektdatenstrukturen eingekapselt sind.Serialisierung von Objekten: kein Thread-Status kann beteiligt sein, oder?

Es gibt andere Lösungen, wo Sie mit aktiven Objekten arbeiten, wo ein Thread auf Benutzerebene an einige Objekte angehängt ist. Und so werden der Programmzähler, der Registerinhalt und der Stapelinhalt plötzlich Teil des Programmzustandes. Soweit ich sehen kann, gibt es keine gute Möglichkeit, solche Dinge zu einem beliebigen Zeitpunkt auf die Festplatte zu serialisieren. Die Threads müssen sich in einem speziellen Zustand ablegen, in dem nichts vom Programmzähler und anderen repräsentiert wird, und somit ihren Ausführungsstatus-Maschinenzustand im Wesentlichen in den expliziten Objektzustand "speichern".

Ich habe eine Reihe von Serialisierungsbibliotheken angeschaut, und soweit ich das beurteilen kann, ist dies eine universelle Eigenschaft.

Die Kernfrage ist dies: Oder ist das eigentlich nicht so? Gibt es da draußen Lösungen zum Speichern/Wiederherstellen, die einen Thread-Status enthalten können, in Bezug darauf, wo in seinem Code ein Thread ausgeführt wird?

Beachten Sie, dass das Speichern eines gesamten Systemstatus in einer virtuellen Maschine nicht zählt, das heißt nicht wirklich den Zustand serialisiert, sondern nur eine Maschine einfriert und verschiebt. Es ist eine offensichtliche Lösung, aber ein bisschen Schwergewicht die meiste Zeit.

Einige Fragen machten deutlich, dass ich nicht klar genug war, um die Idee zu erklären, wie wir die Dinge machen. Wir arbeiten an einem Simulatorsystem, mit sehr strengen Regeln für den Code, der darin ausgeführt werden darf. Insbesondere machen wir eine vollständige Trennung zwischen Objektkonstruktion und Objektstatus. Die Schnittstellenfunktionszeiger werden jedes Mal neu erstellt, wenn Sie das System einrichten, und sind nicht Teil des Status. Der Zustand besteht nur aus bestimmten festgelegten "Attributen", die jeweils eine definierte Get/Set-Funktion haben, die zwischen interner Laufzeitdarstellung und Speicherdarstellung umsetzt. Für Zeiger zwischen Objekten werden sie alle in Namen konvertiert. Also in unserem Design könnte ein Objekt kommen, wie dies in der Lagerung:

Object foo { 
    value1: 0xff00ff00; 
    value2: 0x00ffeedd; 
    next_guy_in_chain: bar; 
} 

Object bar { 
    next_guy_in_chain: null; 
} 

Verknüpfte Listen sind nie wirklich in der Simulationsstruktur stellt jedes Objekt eine Einheit von Hardware irgendeine Art.

Das Problem ist, dass einige Leute dies tun möchten, aber auch Threads als eine Möglichkeit haben, Verhalten zu codieren. "Verhalten" ist hier wirklich eine Mutation des Zustandes der Simulationseinheiten. Grundsätzlich besagt das Design, dass solche Änderungen in atomaren vollständigen Operationen gemacht werden müssen, die aufgerufen werden, ihre Arbeit machen und zurückkehren. Der gesamte Status ist in den Objekten gespeichert. Sie haben ein reaktives Modell, oder es könnte "Lauf bis zur Fertigstellung" oder "ereignisgesteuert" heißen. Die andere Art darüber nachzudenken besteht darin, dass Objekte aktive Threads haben, die an ihnen arbeiten, die wie klassische Unix-Threads in einer ewigen Schleife sitzen und niemals terminieren. Dies ist der Fall, wenn ich versuche zu sehen, ob es vernünftig auf der Festplatte gespeichert werden kann, aber es scheint nicht möglich zu sein, ohne eine darunterliegende VM dazwischenzusetzen.

Update, Oktober 2009: Ein diesbezügliches Dokument wurde 2009 auf der FDL-Konferenz veröffentlicht, siehe this paper über Checkpointing und SystemC.

Antwort

0

Sie sollten nicht versuchen, einen Status zu serialisieren, den Ihr Programm auf der Festplatte hat. Weil Ihr Programm nie die volle Kontrolle über seinen 'Zustand haben wird, es sei denn, es ist vom Betriebssystem erlaubt, in diesem Fall ... es ist Teil des Betriebssystems.

Sie können nicht garantieren, dass ein Zeiger auf einen virtuellen Speicherort wieder auf den gleichen virtuellen Speicherort zeigt (außer für Eigenschaften wie Heap-Begin/Ende, Stack-Begin), da das Betriebssystem zu programmieren Die Auswahlmöglichkeiten für den virtuellen Speicher sind indeterministisch. Die Seiten, die Sie vom Betriebssystem über sbrk oder die höheren Schnittstellen wie malloc anfordern, beginnen überall.

Besser:

  • -Code sauber und Ihr Entwurf überprüfen: Welche Zustandseigenschaften Teil davon sind?
  • Verwenden Sie keine solche Low-Level-Sprache, da der Overhead beim Erstellen von dem, was Sie versuchen zu tun, die Ergebnisse nicht wert ist.
  • Wenn Sie C verwenden müssen, bedeutet, bedeutet, Ihr Leben so einfach wie möglich zu gestalten (berücksichtigen Sie den offsetof-Operator und die Eigenschaften structs haben solche wie das erste Mitglied, beginnend bei Offset 0).

Ich vermute Sie die Entwicklungszeit es serialisiert werden braucht, um die Verknüpfung wollen/deserialisieren spezifische Datenstrukturen, wie verkettete Listen. Seien Sie versichert, was Sie versuchen zu tun ist nicht trivial und es ist viel mehr Arbeit. Wenn Sie darauf bestehen, sollten Sie sich den Speicherverwaltungscode Ihres Betriebssystems und die Paging-Mechanismen des Betriebssystems ansehen. ;-)

EDIT aufgrund der angehängten Frage: Das Design, das Sie sagen, klingt wie eine Art Zustandsmaschine; Objekteigenschaften sind so eingerichtet, dass sie serialisierbar sind, Funktionszeiger können wiederhergestellt werden.

Zuerst in Bezug auf Thread-Zustände in den Objekten: diese nur ganz gleich, ob es kann typisch-gleichzeitige Programmierung Probleme wie Race Conditions, etc. Wenn das der Fall ist, müssen Sie Thread-Synchronisationsfunktionen, wie Mutexe, Semaphore usw. Sie können dann jederzeit auf die Eigenschaften zugreifen, um sie zu serialisieren/deserialisieren und sicher zu sein.

Zweitens, in Bezug auf Objekt-Setup: sieht cool aus, nicht sicher, ob Sie eine binäre oder andere Objektdarstellung haben. Binary vorausgesetzt: Sie können sie leicht serialisieren, wenn Sie die tatsächlichen Strukturen im Speicher darstellen können (was ein bisschen Programmieraufwand ist). Fügen Sie eine Art von Klassen-ID-Wert am Anfang der Objekte und haben Sie eine Nachschlagetabelle, die auf das eigentliche Outfit zeigt. Sehen Sie sich die erste Größe von (id) Bytes an und Sie wissen, welche Art von Struktur Sie haben. Dann wirst du wissen, welche Struktur dort liegt.

Wenn Sie serialisieren/deserialisieren, nähern Sie sich dem Problem so: Sie können die Länge der hypothetisch gepackten (kein Abstand zwischen den Elementen) Struktur nachschlagen, diese Größe zuweisen und die Elemente nacheinander lesen/schreiben. Denken Sie an Offset oder, wenn Ihr Compiler dies unterstützt, verwenden Sie einfach gepackte Strukturen.

BEARBEITEN wegen der kühnen Kernfrage :-) Nein, es gibt keine; nicht für C.

+0

Nun, die Fäden hier sind Dinge in der Sache namens SystemC, im Grunde kooperative nicht preemptive Threading mit Quickthreads oder Windows-Fasern. In einem einzelnen Betriebssystem-Thread. – jakobengblom2

0

Es sieht so aus, als ob Sie eine closure in C++ haben möchten.Wie Sie bereits festgestellt haben, ist in der Sprache kein Mechanismus eingebaut, um dies zu ermöglichen. Soweit ich weiß, ist das grundsätzlich unmöglich. Im Allgemeinen ist es schwierig, in einer Sprache zu arbeiten, die keine VM hat. Sie können es etwas vortäuschen, indem Sie etwas tun, wie Sie vorgeschlagen haben, im Grunde ein Closure-Objekt zu erstellen, das die Ausführungsumgebung/den Ausführungsstatus beibehält. Dann wird dies serialisiert, wenn es sich in einem bekannten Zustand befindet.

Sie werden auch Probleme mit Ihren Funktionszeigern bekommen. Die Funktionen können bei jeder Ladung in verschiedene Speicheradressen geladen werden.

1

Es klingt wirklich wie den Zustand einer virtuellen Maschine zu speichern und in der Lage zu sein, es auf genau die gleiche Weise wiederherzustellen ist genau das, was Sie wollen.

Wenn alles, was Sie brauchen, in der Lage ist, das Programm mit den gleichen Daten wie die vorherige Ausführung zu starten, dann müssen Sie nur speichern und persistente Daten wiederherstellen, sollte der genaue Zustand der einzelnen Threads nicht wirklich egal, da es sich sowieso schnell ändern wird - und die tatsächlichen Adressen der Dinge werden beim nächsten Mal anders sein. Die Verwendung einer Datenbank sollte Ihnen diese Möglichkeit geben.

+0

Nicht ganz: Sie müssen auch in der Lage sein, den Status in einer anderen Implementierung wiederherzustellen, z. B. auf einer anderen Art von Host. Der Thread-Status spielt eine Rolle, wenn er zum Codieren eines Zustandsautomaten wie beispielsweise eines Busprotokolls verwendet wird. – jakobengblom2

2

Ich glaube nicht Serialisierung nur "einige Threads" eines Programms kann arbeiten, da Sie Probleme mit der Synchronisierung (einige der Probleme sind hier beschrieben http://java.sun.com/j2se/1.3/docs/guide/misc/threadPrimitiveDeprecation.html). Wenn Sie Ihr gesamtes Programm beibehalten, ist dies die einzige Möglichkeit, einen konsistenten Zustand zu erhalten.

Worauf Sie achten sollten, ist die orthogonale Persistenz. Es gibt einige prototypische Implementierungen:

http://research.sun.com/forest/COM.Sun.Labs.Forest.doc.external_www.PJava.main.html

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.17.7429

Aber keiner von ihnen erhalten bleiben mehr oder haben eine Menge Anziehungskraft (afaik) gewonnen. Ich denke, Checkpointing ist nicht die beste Lösung. In meinem eigenen Projekt http://www.siebengeisslein.org versuche ich den Ansatz der Verwendung leichter Transaktionen, ein Ereignis zu verschicken, damit der Thread-Status nicht beibehalten werden muss (da am Ende einer Transaktion der Thread-Callstack wieder leer ist und ein Vorgang gestoppt wird) In der Mitte der Transaktion wird alles zurückgerollt, sodass der Thread-Callstack ebenfalls eine Rolle spielt. Sie können wahrscheinlich etwas ähnliches mit jedem OODBMS implementieren.

Eine andere Möglichkeit, Dinge zu betrachten, sind Fortsetzungen (http://en.wikipedia.org/wiki/Continuation, http://jauvm.blogspot.com/). Sie sind eine Möglichkeit, die Ausführung an definierten Codeorten zu unterbrechen (sie bestehen jedoch nicht unbedingt im Thread-Zustand).

Ich hoffe, dies gibt Ihnen einige Startpunkte (aber es gibt keine gebrauchsfertige Lösung zu diesem afaik).

EDIT: Nach dem Lesen Ihrer Klarstellungen: Sie sollten auf jeden Fall in OODBMS schauen. Verteilen Sie jedes Ereignis in einer eigenen Transaktion und kümmern Sie sich nicht um Threads.

0

Ich halte den Thread-Status für ein Implementierungsdetail, das wahrscheinlich nicht serialisiert werden kann. Sie möchten den Zustand Ihrer Objekte speichern - nicht unbedingt, wie sie so geworden sind.

Als ein Beispiel dafür, warum Sie diesen Ansatz verwenden möchten, sollten Sie ein stoßfreies Upgrade in Erwägung ziehen. Wenn Sie Version N Ihrer Anwendung ausführen und ein Upgrade auf Version N + 1 durchführen möchten, können Sie die Objektserialisierung verwenden. Die Threads der Version N + 1 unterscheiden sich jedoch von Threads der Version N.

1

Ein besserer Ansatz als der Versuch, den Programmstatus zu serialisieren, wäre die Implementierung von Crash Only Software mit Datenprüfpunkt. Wie Sie Ihre Daten überprüfen, hängt von Ihrer Implementierungs- und Problemdomäne ab.