Freigeben über


Dieser Artikel wurde maschinell übersetzt.

Der polyglotte Programmierer

ACID-Transaktionen mit STM.NET

Ted Neward

Während dieser Spalte speziell auf Programmiersprachen konzentriert hat, ist es interessant wie Sprache Ideen manchmal über in andere Sprachen Beschnittzugaben können ohne diese direkt ändern.

Ein solches Beispiel handelt es sich um die Sprache C#-Omega (manchmal geschrieben cw, da das griechische Omega-Symbol viel Kleinbuchstaben w auf das US-Tastaturlayout aussieht) von Microsoft Research. Zusätzlich zur Einführung in eine Reihe von Daten und Code Vereinheitlichung Konzepte, die schließlich Ihren Weg in c# und Visual Basic-Sprachen wie LINQ machen, angeboten, C Omega auch oben eine neue Möglichkeit, Parallelität aufgerufen, Chords, die später dieses in eine Bibliothek bekannten, wie Verknüpfungen umgewandelt. Während Verknüpfungen noch nicht, wie der Erstellung dieses Dokuments es in ein Produkt (noch), die Tatsache, dass das gesamte Konzept der Parallelität über eine Bibliothek bereitgestellt werden konnte Chords bedeutet, dass alle run-of-the-mill c# oder Visual Basic (oder anderen .NET-Sprache) Programm konnte, verwenden Sie es.

Anderen Bemühungen ist der Code Verträge-Funktion von der Website von Microsoft DevLabs und in der Ausgabe vom August 2009 MSDN Magazine beschrieben. Entwurf von Vertrag ist eine Sprache-Funktion, die in Sprachen wie Eiffel herausragender wurde und ursprünglich auf .NET über die Microsoft Research-Sprache-Spezifikation # geliefert wurde. Ähnliche Arten von Systemen vertraglichen Garantie haben stammen durch Microsoft Research ebenfalls, einschließlich einer meiner Favoriten, Fugue, welche vorgenommen Verwendung von benutzerdefinierten Attributen und statische Analyse zum Bereitstellen von Clientcode Richtigkeit überprüfen.

Obwohl Code Verträge geliefert wurde noch nicht als formaler Produkt oder mit einer Lizenz, die es, seine Verwendung in der Produktion Software ermöglicht, impliziert die Tatsache, dass es eine Bibliothek als eine eigenständige Sprache existiert noch einmal zwei Dinge. Zunächst werden, dass es (theoretisch) konnte geschrieben, wenn ein Bibliothek von allen .NET Entwickler ausreichend, festgestellt dass ähnliche Arten von Funktionalität zu haben. Und Zweitens, dass (unter der Voraussetzung, dass es ausgeliefert) Funktionalität gesagt konnte für eine Reihe von Sprachen, z. B. c# und Visual Basic.

Wenn Sie ein Design Abtastendes sind, haben Sie Recht. In diesem Monat möchte ich noch eine andere kürzlich Bibliothek angekündigt, die aus der polyglot Language Welt stammen konzentrieren: Software-Transaktionsspeicher oder STM. Die STM.NET-Bibliothek ist über die DevLabs-Website heruntergeladen, aber in starkem Gegensatz zu einigen anderen Implementierungen, die ich bereits erwähnt habe, ist es keine eigenständige Bibliothek Ruft die in Ihrem Programm verknüpft oder als eine statische Analyse-Tool ausgeführt wird – es ist ein Ersatz und eine Ergänzung zu .NET Base Class Library als Ganzes, unter anderem.

Beachten Sie jedoch, dass die aktuelle Implementierung von STM.NET nicht sehr mit aktuellen Visual Studio 2010 Betaversionen, kompatibel, ist sodass die üblichen Haftungsausschlüsse Installation nicht fertig gestellte/Beta/CTP-Software auf Computern, die Sie interessieren gilt doppelt so in diesem Fall. Es sollte Side-by-Side mit Visual Studio 2008 installiert, aber ich weiterhin würde nicht platzieren Sie es auf Ihrem Computer arbeiten. Hier ist ein weiterer Fall, in dem virtuellen Computer Ihre sehr guter Freund ist.

Anfang

Linguistische Hintergrund des STM.NET stammt aus einer Reihe von unterschiedlichen Orten, jedoch ist die grundlegende Idee STM, bemerkenswert einfach und vertraut: Verwalten Sie die Sperren nach Bedarf statt Entwicklern die Möglichkeit, Dinge gleichzeitig (Konzentration auf Sperren und ähnliches) konzentrieren, ermöglichen Sie kennzeichnen, welche Teile des Codes unter bestimmte Merkmale Parallelität freundliche ausführen soll, und lassen Sie das Language-Tool (Compiler oder Interpreter) zu erzwingen. Mit anderen Worten, wie Datenbank-Administratoren und Benutzer, ermöglichen Sie den Programmierer, markieren den Code mit Transaktionssemantik ACID-Format, und lassen Sie die Routinearbeit Verwalten von Sperren auf die zugrunde liegende Umgebung.

Und die STM.NET-Bits nur ein weiterer Versuch zur Verwaltung von Parallelität werden erscheinen, der STM-Aufwand darstellt etwas tiefer als die – es versucht, schalten Sie alle vier Merkmale der Datenbank ACID-Transaktion, die in-Memory-Programmiermodell. Zusätzlich zur Verwaltung der Sperren im Auftrag des Programmierers, bietet das STM-Modell Unteilbarkeit, Konsistenz, Isolation und Dauerhaftigkeit, welche selbst vornehmen kann Programmierung wesentlich einfacher, unabhängig vom Vorhandensein von mehreren Ausführungsthreads.

Betrachten Sie z. B. das folgende Pseudocode (zugegebenermaßen völlig überlastete)-Beispiel:

BankTransfer(Account from, Account to, int amount) {
  from.Debit(amount);
  to.Credit(amount);
}

Was geschieht, wenn die Gutschrift schlägt fehl und löst eine Ausnahme aus? Eindeutig der Benutzer werden nicht glücklich Wenn die Belastung auf das Konto immer noch verbleibt auf dem Datensatz Wenn die Gutschrift auf das Konto nicht vorhanden, ist nun den Entwickler also verfügt einige zusätzliche Aufgaben durchführen:

BankTransfer(Account from, Account to, int amount) {
  int originalFromAmount = from.Amount;
  int originalToAmount = to.Amount;
  try {
    from.Debit(amount);
    to.Credit(amount);
  }
  catch (Exception x) {
    from.Amount = originalFromAmount;
    to.Amount = originalToAmount;
  }
}

Dies würde, zuerst blush scheinen übertrieben. Beachten Sie jedoch, dass je nach der genauen Implementierung der soll- und haben-Methoden, Ausnahmen ausgelöst werden können, vor Abschluss des Vorgangs der soll- oder nach der Gutschrift-Vorgang abgeschlossen ist (aber nicht fertig stellen). Das bedeutet, dass die BankTransfer-Methode muss sicherstellen, dass alle Daten auf die verwiesen wird und bei diesem Vorgang verwendete geht zurück auf genau den Zustand beim Beginn des Vorgangs.

Wenn dieses BankTransfer an alle komplizierter wird – mit drei oder vier Datenelemente gleichzeitig, z. B. – der Wiederherstellungs-Code im Catch-Block soll wirklich hässlichen sehr schnell. Und dieses Muster wird weit häufiger als möchte ich zugeben.

Ein weiterer Punkt anzumerken, isoliert ist. Im ursprünglichen Code konnte ein anderer Thread einen falschen Saldo zu lesen, während es ausgeführt wurde und mindestens eines der Konten beschädigt. Weiter, wenn Sie einfach eine Sperre, um es herum slapped, Sie könnte Deadlocks Wenn die von/bis-Paare wurden nicht immer sortiert. STM kümmert einfach, die für Sie ohne Verwendung von Sperren.

Wenn Sie stattdessen die Sprache angeboten, eine Art von Transaktionsoperationen, z. B. ein atomarer Schlüsselwort, das die Sperrung behandelt und Fehler-Rollback Logik hinter den Kulissen einfach als BEGIN TRANSACTION/COMMIT für eine Datenbank verfügt, wird die Codierung des BankTransfer-Beispiel so einfach wie diese:

BankTransfer(Account from, Account to, int amount) {
  atomic {
    from.Debit(amount);
    to.Credit(amount);
  }
}

Sie müssen zugeben für die dies viel weniger Gedanken ist.

Der STM.NET Ansatz, allerdings wird Bibliothek basiert, ist nicht Recht dies wesentlich, da die Sprache c# ziemlich dieser Grad der syntaktischen Flexibilität zulässt erhalten soll. Sie nun stattdessen mit etwas entlang den Zeilen des arbeiten:

public static void Transfer(
  BankAccount from, BankAccount to, int amount) {
  Atomic.Do(() => {
    // Be optimistic, credit the beneficiary first
    to.ModifyBalance(amount);
    from.ModifyBalance(-amount);
  });
}

Einblicke: Es ist Really eine Sprache ändern

Während der Überprüfung des Neward Spalte sprang eins an mich, als leider eine grundlegende eine falsche Auslegung. Spracherweiterungen in Sprachänderungen benötigen und jener (rein) zu unterteilen, Neward möchte Bibliothek Änderungen. Er versucht, als die zweite klassifizieren, STM.NET – eine Änderung nur Bibliothek – während ich argumentieren würde, die eindeutig nicht ist.

Eine nur-Bibliothek-Erweiterung ist vollständig in die bestehende Sprache implementiert ist. Bibliothek-STM Systemen existieren; diese im Allgemeinen erfordern, dass die Daten, die Transaktionssemantik haben, sollten einige besondere Art, wie z. B. “ TransactionalInt ” deklariert werden. STM.NET ist nicht wie – bietet Transaktionssemantik für normale Daten transparent, einfach aufgrund des Gültigkeitsbereich (dynamisch) einer Transaktion zugegriffen wird.

Dies erfordert jeder Lese- und Schreibzugriff in Code, der ausgeführt wird, innerhalb der Transaktion geändert werden, um weitere Stellen auftreten zugeordnete Anrufe, die erforderliche Sperren zu erhalten, erstellen und Auffüllen von Schattenkopien und so weiter. In unserer Implementierung geändert wir die CLR JIT-Compiler häufig um sehr unterschiedliche Code innerhalb von Transaktionen ausgeführt werden zu erzeugen. Atomare Schlüsselwort ändert (selbst wenn wir Sie über eine Delegate-basierten API angezeigt haben) die Sprachsemantik der eine recht grundlegenden Ebene.

Ich Anspruch auf diese Weise, dass wir die Sprache geändert haben. In einer .NET-Sprache wie c#, werden die Sprachsemantik der implementiert, indem eine Kombination der Quellebene Language-Compiler und seine Annahmen über die Semantik der MSIL, die er ausgibt, wie die CLR die INTEGRITÄTSSTUFE ausgeführt wird. Radikal geändert wir die CLR die Interpretation der Bytecodes, damit ich sagen würde, dass dies die Sprache ändert.

Sagen Sie insbesondere die CLR JIT-Compiler Code wie folgt auftritt:

try { <body> } catch (AtomicMarkerException) {}

Der Code im < Body > (und rekursiv innerhalb von Methoden, die Sie aufruft) ist, stellen Sie sicher, dass Transaktionssemantik dynamisch geändert. Ich sollte Betonen Sie, dass dies absolut nichts mit der Ausnahmebehandlung zu tun hat – es ist lediglich ein Hacker einen atomaren Block zu identifizieren, da die Try-Catch-Anweisung der einzige Mechanismus zum Identifizieren eines lexikalisch Bereichsbezogene Blocks in IL verfügbar ist. Langfristig, sollten wir etwas mehr eine explizite “ atomaren ” Block in der IL-Sprache. Die Delegate-basierten Schnittstelle ist im Hinblick auf diesen ersatz atomaren Block implementiert.

Zusammenfassend ändert der IL-Ebene atomare Block jedoch ausgedrückt, wirklich die Semantik des Codes, die in diese grundlegenden so ausgeführt wird. Dies ist der Grund, warum STM.NET eine neue, wesentlich geänderte CLR-Laufzeit, nicht nur Änderungen an der BCL enthält. Wenn Sie eine vordefinierte CLR-Laufzeit dauerte und mit der BCL aus STM.NET ausgeführt wurde, das Ergebnis würde nicht bieten Ihnen Transaktionssemantik (in der Tat ich bezweifle es funktionieren würde).

– Dr. Dave Detlefs, Architekt, Common Language Runtime, Microsoft

Die Syntax ist nicht ganz so elegant wie eine atomare Schlüsselwort wäre, aber c# verfügt über die Leistungsfähigkeit von anonyme Methoden, um den Codeblock zu erfassen, die den Hauptteil der gewünschten atomaren Block vornehmen würde, und kann daher unter ähnliche Arten von Semantik ausgeführt werden. (Ihr Passport-Konto, aber als des Verfassens dieses Artikels unterstützt der STM.NET Incubation Aufwand nur c#. Es gibt keinen technischen Grund, warum es konnte nicht erweitert werden, um alle Sprachen, aber das Team STM.NET nur konzentriert c# für die erste Version.)

Erste Schritte mit STM.NET

Zuerst wird müssen Sie tun die Microsoft .NET Framework 4 Beta 1 aktiviert die Verwendung von Software Transactional Speicher v1. 0-Bits (einen long-winded an, der ich STM.NET BCL oder einfach STM.NET kürzen werde) von der DevLabs-Website downloaden. Nutzen Sie dort auch Downloaden Sie auch die STM.NET-Dokumentation und Beispiele. Im ersten Fall wird die tatsächliche BCL und STM.NET-Tools und zusätzliche Assemblys und die letztere enthält, zwischen der Dokumentation und die Beispielprojekte, ein Visual Studio 2008-Vorlage für das Erstellen von STM.Net Anwendungen.

Erstellen einer neuen STM.NET-fähigen Anwendung wie jede andere Anwendung, in das Dialogfeld Neues Projekt beginnt (siehe Abbildung 1 ). Auswählen der TMConsoleApplication-Vorlage ist eine Reihe von Faktoren ab, von die einige nicht ganz intuitiv sind. Beispielsweise erfordert als des Verfassens dieses Artikels, die für die STM.NET-Bibliotheken ausgeführt die .NET Anwendung app.config diese wenig Versionsverwaltung Legerdemain:

Abbildung 1 Starten eines neuen Projekts mit der Vorlage TMConsoleApplication

image: Starting a New Project with the TMConsoleApplication Template

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
  <startup> 
    <requiredRuntime version="v4.0.20506"/> 
  </startup>
  ... 
</configuration>

Andere Einstellungen vorhanden sind, aber der RequiredRuntime-Wert ist erforderlich, teilen Sie das CLR-Startprogramm Shim anhand der STM.NET-Version der Common Language Runtime binden. Darüber hinaus bindet die TMConsoleApplication-Vorlage der Mscorlib-Versionen der Assembly und installiert, in dem Verzeichnis, in dem STM.NET installiert ist, anstatt die Versionen, die im Lieferumfang von .NET Framework 3.0 oder 3.5 CLR Aktie System.Transactions-Assemblys. Dies ist erforderlich, wenn Sie zu, da Wenn STM.NET transaktionalen Zugriff für alles, was hinter den Code bereitstellen, den Sie schreiben, er seine eigene Kopie Mscorlib verwenden müssen. Plus, wenn es richtig Interaktion mit anderen Arten von Transaktionen – z. B. die lightweight-Transaktionen bereitgestellt, durch die LTM (Lightweight Transaktions-Manager, Zunächst) – es muss auch eine eigene Version von "System.Transactions" haben.

Abgesehen wird eine Anwendung STM.NET einer herkömmlichen .NET-Anwendung in c# geschrieben und kompiliert, um IL, gegen die restlichen die unveränderte .NET-Assemblys und usw. verknüpft werden. STM.NET-Assemblys, wie die Komponenten COM+ und EnterpriseServices im letzten Jahrzehnt haben einigen Weitere Erweiterungen in diese zur Beschreibung Transaktions-Verhaltensweisen für die Methoden, die Interaktion mit der STM.NET-Transaktionsverhalten, aber ich Gelegenheit, rechtzeitig.

Hallo, STM.NET

Als möglicherweise mit der Axum-Beispiel in der Ausgabe vom September 2009 MSDN Magazine, eine herkömmliche Hello World-Anwendung schreiben, wie der Ausgangspunkt für die STM.NET, als Sie tatsächlich schwerer ist zunächst vorstellen größtenteils ist Wenn Sie es ohne Belang für Transaktionen zu schreiben, genau identisch mit der herkömmlichen c# Hello World. Wenn Sie darauf, um das Transaktionsverhalten STM.NET nutzen schreiben, müssen Sie die Tatsache berücksichtigen, Schreiben von Text auf der Konsole, in der Tat ist eine un-undoable-Methode (mindestens so weit betrifft STM.NET), was bedeutet, dass bei dem Versuch, eine Console.WriteLine-Anweisung ein Rollback schwierig ist.

Daher stattdessen let’s akzeptieren ein einfaches Beispiel für das STM.NET-Benutzerhandbuch als eine schnelle Demonstration der STM.NET-Bits. Ein Objekt (MyObject bezeichnet) besteht aus zwei private Zeichenfolgen und eine Methode, um diese zwei Zeichenfolgen auf einige Werte-Paar festzulegen:

class MyObject {
  private string m_string1 = "1";
  private string m_string2 = "2";

  public bool Validate() {
    return (m_string1.Equals(m_string2) == false);
  }
  public void SetStrings(string s1, string s2) {
    m_string1 = s1;
    Thread.Sleep(1);   // simulates some work 
    m_string2 = s2;
  }
}

Da die Zuordnung des Parameters an das Feld selbst eine atomare Operation ist, spielt gibt es keine um Parallelität vorhanden. Aber so, wie mit der BankAccount-Beispiel weiter oben gezeigt, entweder beide festgelegt werden oder keines von beiden, und sollen keine partielle Updates angezeigt werden sollen – eine Zeichenfolge festgelegt wird, jedoch nicht anderen – während der Set-Vorgang. Sie müssen zwei Threads blind die Zeichenfolgen immer wieder neu, und einem dritten thread zur Überprüfung des Inhalts der MyObject-Instanz erzeugen eine Verletzung der Berichterstellung, im Ereignisprotokoll überprüfen false zurückgibt (siehe Abbildung 2 ).

Abbildung 2 Manuelles Überprüfen von atomaren Updates MyObject

[AtomicNotSupported]
static void Main(string[] args) {
  MyObject obj = new MyObject();
  int completionCounter = 0; int iterations = 1000;
  bool violations = false;

  Thread t1 = new Thread(new ThreadStart(delegate {
    for (int i = 0; i < iterations; i++)
      obj.SetStrings("Hello", "World");
    completionCounter++;
  }));

  Thread t2 = new Thread(new ThreadStart(delegate {
    for (int i = 0; i < iterations; i++)
      obj.SetStrings("World", "Hello");
    completionCounter++;
  }));

  Thread t3 = new Thread(new ThreadStart(delegate {
    while (completionCounter < 2) {
      if (!obj.Validate()) {
        Console.WriteLine("Violation!");
        violations = true;
      }
    }
  }));

  t1.Start(); t2.Start(); t3.Start();
  while (completionCounter < 2)
    Thread.Sleep(1000);

  Console.WriteLine("Violations: " + violations);
...

Beachten Sie, dass dieses Beispiel erstellt wird, wie Validierung schlägt fehl, wenn die beiden Zeichenfolgen in Obj auf das gleiche festgelegt sind, der angibt, dass Thread t1 SetStrings(“Hello”, “World”) teilweise aktualisiert wird (wobei ersten “ Hello ” an die zweite “ Hello ” festlegen, indem Sie t2 übereinstimmen).

Ein oberflächliche Blick auf die Implementierung von SetStrings zeigt an, dass dieser Code kaum threadsicher ist. Wenn ein Thread-Schalter in der Mitte auftritt (die wahrscheinlich den Thread.Sleep-Aufruf angegeben wird, der den derzeit ausgeführten Thread führt um seine Time Slice zu geben), konnte ein anderer Thread leicht in die Mitte der SetStrings erneut, wechseln die MyObject-Instanz in einem ungültigen Zustand versetzen. Führen Sie es, und mit genügend Iterationen startet Verletzungen angezeigt werden. (Auf meinem Laptop musste führen Sie es zweimal, bevor ich habe die Verletzungen Nachweis, dass nur weil es ausgeführt, ohne wird ein Fehler einmal bedeuten nicht im Code einen Fehler Parallelität besitzt.)

Ändern diese Option, um STM.NET verwenden erfordert nur eine kleine Änderung an der MyObject-Klasse, wie in Abbildung 3 .

Abbildung 3 Validating MyObject mit STM.NET

class MyObject {
  private string m_string1 = "1";
  private string m_string2 = "2";

  public bool Validate() {
    bool result = false;
    Atomic.Do(() => { 
      result = (m_string1.Equals(m_string2) == false);
    });
    return result;
  }

  public void SetStrings(string s1, string s2) {
    Atomic.Do(() => {
      m_string1 = s1;
      Thread.Sleep(1); // simulates some work 
      m_string2 = s2;
    });
  }
}

Wie Sie sehen können, war die einzige Änderung erforderlich, umschließen den Nachrichtentext überprüfen und SetStrings in atomare Methoden, die mit der Atomic.Do-Operation. Nun, angezeigt, wenn ausführen, keine Verletzungen.

Transaktionale Affinität

Aufmerksamen Leser werden bemerkt haben das [AtomicNotSupported]-Attribut am oberen Rand der Main-Methode im Abbildung 2, und vielleicht an seinen Zweck gefragt, oder sogar schon einmal gefragt, wenn Sie denselben Zweck wie die Attribute von COM+-Tagen bedient. Wie sich herausstellt, ist völlig richtig: Die STM.NET-Umgebung benötigt Unterstützung zu verstehen, ob Methoden aufgerufen, während eine atomarische Block Transaktion geeignet sind, damit es die notwendigen und wünschenswert, dass für diese Methoden unterstützen kann.

Drei Attribute sind in der aktuellen Version der STM.NET verfügbar:

  • AtomicSupported – die Assembly-Methode, Feld oder delegieren Transaktionsverhalten unterstützt und kann verwendet werden, innerhalb oder außerhalb der atomare Blöcke erfolgreich.
  • AtomicNotSupported – die Assembly, Methode oder Delegat Transaktionsverhalten nicht unterstützt und daher sollte nicht innerhalb eines atomarischen Blöcke verwendet werden.
  • AtomicRequired – die Assembly, die Methode, Feld oder Delegaten unterstützt nicht nur das Transaktionsverhalten, sollte nur innerhalb eines atomarischen Blöcke (daher garantieren, dass mit diesen Artikel immer unter Transaktionssemantik durchgeführt werden) verwendet werden.

Technisch gesehen ist eine vierte, AtomicUnchecked, das zum STM.NET signalisiert, dass dieses Element Periode geprüft werden sollten nicht vorhanden. Es ist als eine Schraffur Escape vorgesehen, um zu vermeiden, überprüfen den Code vollständig.

Das Vorhandensein des Attributs AtomicNotSupported ist, was das System STM.NET eine AtomicContractViolationException ausgelöst wird, wenn, der folgende (naive) Code versucht wird führt:

[AtomicNotSupported]
static void Main(string[] args) {
  Atomic.Do( () => {
    Console.WriteLine("Howdy, world!");
  });

  System.Console.WriteLine("Simulation done");
}

Da die System.Console.WriteLine-Methode nicht mit AtomicSupported markiert ist, löst die Atomic.Do-Methode die Ausnahme aus, wenn durch den Aufruf in den atomaren Block erkennt. Dieses Bit der Sicherheit wird sichergestellt, dass nur Transaktion freundliche Methoden innerhalb der atomare Block ausgeführt werden und stellt dieses zusätzliche Bit der Sicherheit für den Code.

Hello, STM.NET (Teil 2)

Was geschieht, wenn Sie wirklich, wirklich das herkömmliche Hello-World schreiben möchten? Was geschieht, wenn Sie möchten eine Zeile in der Konsole ausgeben (oder in eine Datei schreiben, oder führen Sie einige nicht transaktionale Verhalten) zusammen mit zwei anderen Transaktionsvorgänge, sondern nur aus drucken, wenn beide dieser andere Operationen erfolgreich? STM.NET bietet drei Möglichkeiten, um diese Situation zu behandeln.

Zunächst können Sie den nicht transaktionalen Vorgang außerhalb der Transaktion (und nur, nachdem die Transaktion ein Commit) ausführen, indem des Codes innerhalb eines Blocks an Atomic.DoAfterCommit übergeben. Da der Code innerhalb dieses Blocks in der Regel werden Daten erstellt oder geändert von innerhalb der Transaktion verwenden möchten, wird DoAfterCommit einen Kontextparameter, der von innerhalb der Transaktion an den Codeblock als einzigen Parameter übergeben wird.

Zweitens können Sie eine kompensierende Aktion erstellen, die ausgeführt wird, wenn die Transaktion letztendlich fehlschlägt, durch den Aufruf von Atomic.DoWithCompensation, die die (erneut) einen Kontextparameter zum Marshallen von Daten innerhalb der Transaktion, die ein Commit hat oder Ausgleichen der Codeblock (je nach Bedarf).

Drittens können Sie ganz wechseln und erstellen eine Transaktions Resource Manager (RM), die mit der STM.NET-Transaktionssystem teilnehmen kann. Dies ist tatsächlich weniger schwieriger, als es scheint möglicherweise – nur erben von der STM.NET-Klasse TransactionalOperation, die OnCommit und OnAbort-Methoden, die Sie überschreiben enthält, um das entsprechende Verhalten in beiden Fällen bereitzustellen. Bei der Verwendung dieses neuen Typs RM (Debitorenverwaltung) rufen Sie OnOperation zu Beginn Ihrer Arbeit mit (effektiv eintragen der Ressource in die Transaktion STM.NET). Dann-Aufruf FailOperation für den Fall, dass die umgebenden Vorgänge schlagen fehl.

Folglich können transaktionell in einigen textbasierte Stream geschrieben werden soll, Sie einen Text anfügen Ressourcen-Manager wie dargestellt in Abbildung 4 schreiben. Diese dann können Sie – in der Tat aufgrund des Attributs [atomar Required] erfordert die – einige Textstream über TxAppender während innerhalb eines atomarischen Blocks geschrieben (siehe Abbildung 5 ).

Abbildung 4 A Transactional Ressourcen-Manager

public class TxAppender : TransactionalOperation {
  private TextWriter m_tw;
  private List<string> m_lines;

  public TxAppender(TextWriter tw) : base() {
    m_tw = tw;
    m_lines = new List<string>();
  }

  // This is the only supported public method
  [AtomicRequired]
  public void Append(string line) {
    OnOperation();

    try {
      m_lines.Add(line);
    }
    catch (Exception e) {
      FailOperation();
      throw e;
    }
  }

  protected override void OnCommit() {
    foreach (string line in m_lines) {
      m_tw.WriteLine(line);
    }
    m_lines = new List<string>();
  }

  protected override void OnAbort() {
    m_lines.Clear();
  }
}

Abbildung 5 mithilfe von TxAppender

public static void Test13() {
  TxAppender tracer = 
    new TxAppender(Console.Out);
  Console.WriteLine(
    "Before transactions. m_balance= " + 
    m_balance);

  Atomic.Do(delegate() {
    tracer.Append("Append 1:  " + m_balance);
    m_balance = m_balance + 1;
    tracer.Append("Append 2:  " + m_balance);
  });
            
  Console.WriteLine(
    "After transactions. m_balance= " 
    + m_balance);

  Atomic.Do(delegate() {
    tracer.Append("Append 1:  " + m_balance);
    m_balance = m_balance + 1;
    tracer.Append("Append 2:  " + m_balance);
  });

  Console.WriteLine(
    "After transactions. m_balance= " 
    + m_balance);
}

Dies ist offensichtlich länger Route und werden nur in bestimmten Szenarios geeignet. Es kann für einige Arten von Medientypen fehlschlagen, aber in den meisten Fällen, wenn alle tatsächliche irreversible Verhalten der OnCommit-Methode verzögert wird, dies ist ausreichend für einen Großteil Ihrer Transaktionsnachrichten in-Process-Anforderungen.

Versetzen STM.NET auf Arbeit

Arbeiten mit einer STM-System nimmt etwas gewöhnungsbedürftig, aber sobald Sie acclimated sind, ohne es arbeiten kann fühlen Schwächen. Betrachten Sie einige der möglichen stellen, in dem STM.NET mit Codierung vereinfachen kann.

Beim Arbeiten mit andere transaktive Ressourcen angeschlossen STM.NET in vorhandenen transaktive Systeme schnell und einfach Atomic.Do die einzige Quelle von Transaktiver Code in Ihrem System vornehmen. Die STM.NET-Beispiele veranschaulichen dies im Bereitstellen von Nachrichten an eine MSMQ private Warteschlange TraditionalTransactions-Beispiel und wodurch es offensichtlich, wenn atomarische Block fehlschlägt, wird keine Nachricht an die Warteschlange bereitgestellt. Dies ist wahrscheinlich die offensichtlichsten Verwendung.

In Dialogfeldern – insbesondere für mehrere Schritte umfassenden Assistenten Prozesse oder Einstellungen Dialoge – die Fähigkeit, Änderungen an den Einstellungen oder das Dialogfeld Datenmember beim Rollback der Benutzer die Abbrechen-Schaltfläche drückt wertvollen ist.

Komponententests, z. B. NUnit, MSTest und anderen Systemen großartige Aufwand, um sicherzustellen, dass, wenn richtig geschrieben ist, Tests Ergebnisse ein Test mit dem nächsten Speicherverluste können nicht auszuüben. STM.NET Produktionsstatus erreicht hat, können NUnit und MSTest Umgestaltung Ihrer Testfall Ausführung Codes, STM-Transaktionen verwenden, um die Testergebnisse von anderen, isolieren generieren einen Rollback am Ende jeder Testmethode, und vermeiden somit alle Änderungen, die durch den Test generiert möglicherweise. Sogar noch ein Test, der ein AtomicUnsupported-Methode aufruft wird zur Ausführungszeit testen, als Fehler gekennzeichnet werden, anstatt im Hintergrund verliert des Tests ergibt sich einige Mittel außerhalb der Testumgebung (z. B. Datenträger oder einer Datenbank).

STM.NET können auch in der Domäne Objektimplementierung-Eigenschaft verwendet werden. Obwohl die meisten Domänenobjekte relativ einfach über Eigenschaften, Zuweisen zu einem Feld oder Zurückgeben des Feldes value, komplexere Eigenschaften mit mehreren - Schritt-Algorithmen ausgeführt, das Risiko, dass mehrere Threads, die partielle Aktualisierungen anzeigen, (Wenn ein anderer Thread die-Eigenschaft bei seinen Satz aufruft) oder Phantom aktualisiert (im Ereignisprotokoll ein anderer Thread die Eigenschaft während dessen festgelegt ruft und das ursprüngliche Update schließlich aufgrund von einen Validierungsfehler irgendeiner Form weggeworfen ist).

Noch interessanter, Wissenschaftlern außerhalb von Microsoft sind Suchen in Transaktionen in Hardware erweitern, so, dass eines Tages, aktualisieren ein Objekt-Feld oder eine lokale Variable einer Transaktion durch den Speicher auf der Hardwareebene geschützt werden konnte chip selbst, die Transaktion blindingly schnell im Vergleich zu heutigen Methoden vornehmen.

Allerdings hängt wie bei Axum, Microsoft Ihr Feedback zu bestimmen, wenn diese Technologie verfolgt und productizing, wenn Sie diese Idee aufregende suchen oder interessant oder, dass es wichtig, ihre praktischen Codierung etwas fehlt, damit Sie Ihnen zögern nicht lohnt. 

Ted Neward* ist ein Principal mit Neward und Partnern, ein unabhängiger fest spezialisiert .NET- und Java-Unternehmenssystemen. Er verfügt über zahlreiche Bücher geschrieben, ist ein Microsoft MVP-Architekt, INETA-Sprecher und zum Kursleiter PluralSight. Ted ted@tedneward.com erreichen oder seinen Blog unter <blogs.tedneward.com> lesen.*

Dank an die folgenden technischen Experten für die Überprüfung dieses Artikels: Dave Detlefs und Dana Groff