2010-07-21 11 views
8

Ich schreibe eine Anwendung mit einer mehrschichtigen Kommunikationsschnittstelle.
Dies wurde getan, um die Kommunikation von der Benutzeroberfläche der Anwendung zu abstrahieren und sie auch skalierbarer/wartbarer zu machen.
Zum Beispiel:Umgang mit Race-Bedingungen in C#

alt text

Betrachten Sie jedes Feld in der obigen Abbildung als separate Klasse.
Das Generic Comms Interface füllt String-Variablen, die die abgewickelten Daten und die "Gesundheit" der Kommunikation beschreiben, die wiederum durch eine Reihe von öffentlichen Funktionsaufrufen in die Anwendung kopiert werden. Zum Beispiel würde die Anwendung einen Aufruf an dem App-Sub-System machen:

class Application 
{ 
    private void SomeUpdateFunction() 
    { 
     this.textBox1.AppendText(this.AppSubSystem.GetText()); 
    } 
} 

class AppSubSystem 
{ 
    public string GetText() 
    { 
     return this.GenericCommsInterface.GetText(); 
    } 
} 

class GenericCommsInterface 
{ 
    public string GetText() 
    { 
     string sRetVal = this.sText; // sText is populated by other functions in the class. 
     this.sText = null; // Suspected race condition is here. 
     return sRetVal; 
    } 
} 

sText wird bevölkert asynchron durch andere Funktionen in der Klasse.
Ich glaube, dass ein Wettlauf zwischen string sRetVal = this.sText; und der folgenden Zeile this.sText = null; stattfindet.
Kann jemand vorschlagen, diesen Race Condition zu vermeiden oder zu verhindern? Würde StringBuilder helfen, oder gibt es einen anderen Weg, dass ich das tun sollte?

Antwort

4

Sie sollten wahrscheinlich eine Sperre erwerben, wann immer Sie möchten this.sText - in den Funktionen, die es zu aktualisieren, sowie Ihre GetText Funktion. Dies würde sicherstellen, dass immer nur ein Thread mit ihm rumhängt, da (vorausgesetzt, Ihr Thread hat die Sperre) andere Threads sitzen und warten, bis der aktuelle Thread fertig ist.

Ich würde empfehlen, einen StringBuilder zu verwenden, teilweise um das Sperren zu vereinfachen, wie das Sperren einer Zeichenfolge, die interniert wurde, oder eines mitten in der gesperrten Operation (und somit aus der Sicht eines Außenstehenden entsperrt) verursacht wirklich schlechtes mojo. So etwas würde helfen:

lock (this.sbText) 
{ 
    sRetVal = this.sbText.ToString(); 
    this.sbText.Length = 0; 
} 

Alternativ Sie auf this sperren könnte, aber das ist hässlich - Ihre Schlösser sollten drin sein, so privat wie möglich, um seltsame Nebenwirkungen zu vermeiden (wie wenn eine andere Objekt versuchte, eine Sperre für dieses Objekt zu erhalten - dies konnte nicht ausgeführt werden, während sbText geändert wurde.

+1

Sehr schlecht zu 'sperren' auf ein Objekt nicht garantiert, um über den Thread-Zugang stabil zu sein - Sperren sind 'Advisory', dass jeder sie verwenden/ehren muss. Dies ist besonders schlimm, weil Sie das Sperrobjekt ständig ändern (indem Sie die Variable, die es enthält, auf null setzen). –

+0

Guter Punkt.Ein weiterer Grund, einen StringBuilder zu verwenden. – cHao

+0

Danke für die Tipps! Ich habe 'private string sText' durch' private StringBuilder cText' ersetzt und die Sperren implementiert. Es funktioniert super! Der Race-Zustand ist verschwunden. Kudos! –

1
public string GetText() 
{ 
    lock(someObject) 
    { 
     string sRetVal = this.sText; // sText is populated by other functions in the class. 
     this.sText = null; // Suspected race condition is here. 
     return sRetVal; 
    } 
}  

in Ihrem Set

lock(someObject) 
{ 
    //... 
    this.sText = value; 
} 
+0

Dies wird * NICHT * tun - eine neue Zeichenfolge könnte nach dem Lesen aber vor dem Null geschrieben werden. Der gesamte Vorgang muss geschützt werden, nicht nur die Teile. –

+0

Internierung wird Sie in den unteren Regionen beißen .. Verriegelung an einer Schnur ist schlimmer als gar nicht zu sperren. –

+0

Ich stimme nicht zu, aber ich habe mein Lock-Objekt überhaupt nicht definiert, geschweige denn, es als String zu definieren. Ich nahm an, er könnte den Kern des Dinges nehmen und die Lücken füllen. –

1

Dieser Code ganz sicher in einer Thread-Umgebung nicht funktionieren, wie Sie sText nicht zu schützen sind. Sie müssen alle sperren, die darauf zugreifen.

+1

Es wird funktionieren - * manchmal *. Zu anderen Zeiten werden Nachrichten auf mysteriöse Weise verschwinden. – cHao

+1

Das Arbeiten funktioniert manchmal nicht. –

+3

Ich arbeite 8 (ish) Stunden pro Tag. Bin ich arbeitslos? :) –