Serialisierung von Objekten: Es kann kein Thread-Status involviert sein, oder?

8

Ich untersuche die Grundprinzipien des Speicherns des Zustands eines ausführenden Programms auf der Festplatte, und bringe es wieder ein. 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.

Es gibt andere Lösungen, bei denen Sie mit aktiven Objekten arbeiten, bei denen 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 keinen guten Weg, 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 betrachtet, und soweit ich das beurteilen kann, handelt es sich um eine universelle Eigenschaft.

Die Kernfrage lautet: Oder ist das eigentlich nicht so? Gibt es Save / Restore-Lösungen, die 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 gezählt wird. Dies bedeutet nicht, dass der Status serialisiert wird, sondern nur ein Computer eingefroren und verschoben wird. Es ist eine offensichtliche Lösung, aber ein bisschen Schwergewicht die meiste Zeit.

Einige Fragen haben deutlich gemacht, dass ich nicht klar genug war, um die Idee zu erklären, wie wir etwas 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. In unserem Design könnte also ein Objekt im Speicher so aussehen:

%Vor%

Verkettete Listen sind in der Simulationsstruktur nie wirklich vorhanden, jedes Objekt repräsentiert eine Einheit von Hardware irgendeiner Art.

Das Problem ist, dass einige Leute dies tun wollen, aber auch Threads als Möglichkeit haben, Verhalten zu programmieren. "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 enden. Dies ist der Fall, dass ich versuche, zu sehen, ob es vernünftig auf der Festplatte gespeichert werden kann, aber es scheint nicht möglich, ohne dazwischen eine VM darunter zu legen.

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

    
jakobengblom2 08.10.2008, 18:03
quelle

7 Antworten

2

Ich glaube nicht, dass nur einige "Threads" eines Programms serialisiert werden können, da Sie Probleme mit der Synchronisation haben werden (einige der Probleme sind hier beschrieben Ссылка ). Daher ist das Fortbestehen des gesamten Programms der einzig gangbare Weg, um einen konsistenten Zustand zu erreichen.

Sie könnten nach orthogonaler Persistenz suchen. Es gibt einige prototypische Implementierungen:

Ссылка

Ссылка

Aber keiner von ihnen ist mehr gepflegt oder hat viel Anziehungskraft (afaik) gewonnen. Ich denke, Checkpointing ist nicht die beste Lösung. In meinem eigenen Projekt Ссылка versuche ich den Ansatz, leichtgewichtige Transaktionen zu verwenden, um ein Ereignis zu versenden, damit der Thread-Status nicht beibehalten werden muss (seit Am Ende einer Transaktion ist der Thread-Callstack wieder leer und wenn eine Operation mitten in der Transaktion gestoppt wird, wird alles zurückgesetzt, so dass 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 ( Ссылка , Ссылка ). Sie sind eine Möglichkeit, die Ausführung an definierten Codeorten zu unterbrechen (sie bestehen jedoch nicht unbedingt im Thread-Zustand).

Ich hoffe, das gibt Ihnen einige Startpunkte (aber es gibt keine gebrauchsfertige Lösung für diesen afaik).

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

    
jiriki 08.10.2008 18:48
quelle
1

Es klingt wirklich so, als würde man den Zustand einer virtuellen Maschine speichern und sie genau so wiederherstellen können, wie Sie wollen.

Wenn Sie nur das Programm mit den gleichen Daten starten möchten wie die vorherige Ausführung, dann müssen Sie nur persistente Daten speichern und wiederherstellen. Der genaue Zustand jedes Threads sollte nicht wirklich wichtig sein weil 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 Fähigkeit sowieso geben.

    
Greg Rogers 08.10.2008 18:29
quelle
1

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

    
paxos1977 08.10.2008 18:58
quelle
0

Es sieht so aus, als ob Sie in C ++ eine Sperrung 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 jedem Laden in verschiedene Speicheradressen geladen werden.

    
Matt Price 08.10.2008 18:22
quelle
0

Ich betrachte den Thread-Status als Implementierungsdetail, das wahrscheinlich nicht serialisiert werden kann. Sie möchten den Zustand Ihrer Objekte speichern - nicht unbedingt, wie sie so sind, wie sie sind.

Als ein Beispiel dafür, warum Sie diesen Ansatz verwenden möchten, sollten Sie ein hitless upgrade in Betracht 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 "Version N + 1" -Threads unterscheiden sich jedoch nicht von den Threads der Version N.

    
bog 08.10.2008 18:58
quelle
0

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

Sie können nicht garantieren, dass ein Zeiger auf einen virtuellen Speicherort erneut auf den gleichen virtuellen Speicher verweist (mit Ausnahme von Eigenschaften wie heap-begin / end, stack-begin) Programmieren die Betriebssystem-Auswahlmöglichkeiten für 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 überprüfen Sie Ihr Design: Welche Zustandseigenschaften sind ein Teil davon?
  • Verwenden Sie keine solche Sprache auf niedriger Ebene, da der Overhead bei der Erstellung Ihrer Versuche die Ergebnisse nicht wert ist.
  • Wenn Sie C verwenden müssen, meinen Sie, damit Sie Ihr Leben so einfach wie möglich gestalten können (berücksichtigen Sie den offsetof-Operator und die Eigenschaften structs haben ein ähnliches erstes Element, beginnend bei offset 0).

Ich vermute Sie möchten die Entwicklungszeit verkürzen, die benötigt wird, um bestimmte Datenstrukturen zu serialisieren / deserialisieren , z. B. verknüpfte Listen. Sei versichert, was du versuchst 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. ; -)

BEARBEITEN aufgrund der angehängten Frage: Das von Ihnen angegebene Design klingt wie eine Art Zustandsmaschine; Objekteigenschaften sind so eingerichtet, dass sie serialisierbar sind, Funktionszeiger können wiederhergestellt werden.

Erstens, zu Thread-Zuständen in Objekten: diese sind nur wichtig, wenn es typische Probleme bei gleichzeitigem Programmieren gibt, wie etwa Race Conditions usw. Wenn das der Fall ist, benötigen Sie Thread-Synchronisations-Funktionalität, wie z als Mutexe, Semaphore, etc. Dann können Sie jederzeit auf die zu serialisierenden / zu deserialisierenden Eigenschaften zugreifen und sicher 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 am Anfang der Objekte einen Klassen-ID-Wert ein und verwenden Sie eine Nachschlagetabelle, die auf das tatsächliche Outfit verweist . 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.

Gehen Sie bei der Serialisierung / Deserialisierung folgendermaßen vor: Sie können die Länge der hypothetisch gepackten Struktur (kein Abstand zwischen den Elementen) 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.

    
mstrobl 08.10.2008 18:22
quelle
0

So etwas wurde für Java in JSR 323 vorgeschlagen:

Ссылка

wurde aber nicht als zu theoretisch akzeptiert:

Ссылка

Wenn Sie den Links folgen, können Sie einige interessante Forschung zu diesem Problem finden.

    
Alex Miller 08.10.2008 21:47
quelle