2010-07-21 5 views
8

J'écris une application avec une interface de communication en couches. Cela a été fait pour extraire les communications de la partie interface utilisateur de l'application et également pour la rendre plus évolutive/maintenable.
Par exemple:Gestion des conditions de course en C#

alt text

Tenir compte de chaque boîte dans la figure ci-dessus comme une catégorie distincte.
L'interface de communication générique remplit les variables de chaîne décrivant les données traitées et les communications "health", qui sont à leur tour copiées vers l'application via une série d'appels de fonction publique. Par exemple, l'application ferait un appel à l'App-Sub-System:

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 est peuplée de manière asynchrone par d'autres fonctions dans la classe.
Je crois qu'une condition de concurrence se produit entre string sRetVal = this.sText; et la ligne suivante this.sText = null;.
Quelqu'un peut-il suggérer un moyen d'éviter ou d'éviter cette condition de concurrence? Serait l'aide StringBuilder aide, ou est-ce qu'il y a une autre façon que je devrais faire cela?

Répondre

4

Vous devriez probablement acquérir un verrou à chaque fois que vous voulez toucher this.sText - dans les fonctions qui le mettent à jour, ainsi que votre fonction GetText. Cela garantirait que seul un thread à la fois joue avec lui, car (en supposant que votre thread a le verrou) d'autres threads s'asseoiront et attendront jusqu'à ce que le thread en cours soit terminé. Je vous recommande d'utiliser un StringBuilder, en partie pour simplifier le verrouillage, pour verrouiller une chaîne qui a été internée, ou qui a été désactivée au milieu de l'opération verrouillée (et donc déverrouillée, du point de vue d'un outsider). cause vraiment mauvais mojo. Quelque chose comme cela contribuerait à:

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

Sinon, vous pouvez verrouiller this, mais c'est laid - vos serrures doivent être à l'intérieur, aussi privée que possible, afin d'éviter des effets secondaires étranges (comme si un autre objet essayait d'acquérir un verrou sur cet objet - il ne pouvait pas le faire pendant que sbText était en train d'être modifié).

+1

Très mauvais à 'verrouiller' sur un objet qui n'est pas garanti stable à travers l'accès au thread - les verrous sont 'consultatifs' en ce que tout le monde doit les utiliser/les honorer. Ceci est particulièrement mauvais car vous continuez à changer l'objet lock (en définissant la variable qui le contient sur null). –

+0

Bon point.Une autre raison d'utiliser un StringBuilder. – cHao

+0

Merci pour les conseils! J'ai remplacé 'private string sText' par' private StringBuilder cText' et j'ai implémenté les verrous. Cela fonctionne très bien! La condition de course a disparu. Gloire! –

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; 
    } 
}  

dans votre jeu

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

Cela ne * PAS * le faire - une nouvelle chaîne pourrait être écrite après la lecture mais avant la null. L'ensemble de l'opération doit être protégé, pas seulement les parties. –

+0

interner va vous mordre dans les régions inférieures .. verrouillage sur une chaîne est pire que pas de verrouillage du tout. –

+0

Je ne suis pas en désaccord, mais je n'ai pas du tout défini mon objet lock, et encore moins le définir comme string. Je supposais qu'il pourrait prendre l'essentiel de la chose et remplir les blancs. –

1

Ce code certainement ne fonctionnera pas dans un environnement fileté que vous ne protégez pas sText. Vous devez verrouiller tout le monde qui y accède.

+1

Ça va marcher - * parfois *. D'autres fois, les messages disparaîtront mystérieusement. – cHao

+1

Travailler parfois ne fonctionne pas. –

+3

Je travaille 8 (ish) heures par jour. Suis-je au chômage? :) –

Questions connexes