2011-01-16 2 views
1

J'ai une classe Singleton qui dépend fortement du fichier XML qu'elle utilise comme base de données. Au constructeur, le fichier XML est lu et un FileSystemWatcher surveille tout autre changement.Est-ce que 'lock (this)' convient à la synchronisation de chaque fonction membre?

Maintenant, si des changements se produisent, je vais lire à nouveau les données du fichier XML mais à ce stade, les fonctions non de classe doivent être accessibles jusqu'à ce que le fichier XML soit rechargé.

Ma question est peut-je utilise simplement this comme objet de synchronisation (en rechargeant fichier XML) et ne pas apporter de modifications aux fonctions au lieu de mettre un grand lock sur toutes les fonctions?

Répondre

5

lock(this) est mieux évité - il ya un cas de bord que un autre code non apparenté pourrait également le verrouiller, causant peut-être même un interblocage.

Une meilleure approche est:

private readonly object lockObj = new object(); 

Et puis lock(lockObj) - puisque c'est privé, vous évitez ce bord-cas.

Une autre stratégie consiste à charger toutes les données dans un objet encapsulé immuable; alors vous pouvez tout changer en mettant à jour une seule référence; et une assignation de référence est garantie être atomique. Cela permet:

private SomeModel model; 
public void Refresh() { 
    SomeModel newModel = new ... 
    // fully load etc 
    ... 
    model = newModel; 
} 

Cela fonctionne mieux si vous prenez toujours un instantané, par exemple au lieu de

var foo = model.Foo; 
var bar = model.Bar; 

Vous utilisez:

var snapshot = model; 
var foo = snapshot.Foo; 
var bar = snapshot.Bar; 

Depuis maintenant, nous savons que Foo et Bar sont de le même modèle.

+0

Suis-je ici: Parce que j'utilise le motif Singleton et qu'il charge des données dans le constructeur, je peux simplement changer '_instance' (je veux dire la référence interne à un objet singleton) à un nouveau' MyClass' (singleton class) et tout est fait. – Xaqron

+0

@Xaqron - Je pensais encapsuler ** dans ** le singleton, mais tout ce qui fonctionne pour vous. Notez que si vous pouvez le "nouveau", ce n'est pas vrai singleton. –

+0

Vous avez raison. Je ne peux pas le renouveler mais le concept est sympa.Merci – Xaqron

5

Ne pas lock sur this. Déjà. En effet, le code que vous ne contrôlez pas peut se bloquer sur votre objet et aboutir à un scénario d'interblocage très difficile à détecter.

Au lieu de cela, utilisez un objet dédié lock:

private readonly object locker = new object(); 

Puis:

lock(locker) { 
    // something something 
} 

Depuis locker est marqué comme private, vous n'avez pas à vous soucier de code externe à votre objet de verrouillage de votre objet.

+0

+1, mais! exactement la même réponse avec la marque en même temps :) –

+0

C'est déjà ce que je fais. L'inconvénient dans mon scénario est que chaque fonction serait comme ceci: 'myFunction() {lock (_privateLock) {// corps de la fonction} // fin du verrou} // fin de la fonction' – Xaqron

+0

Corollaire: Ne pas verrouiller sur les objets des autres, soit. Ils auraient pu utiliser 'lock (this)'. Je pense que le verrouillage sur les instances 'private' (ou peut-être dans certains cas' internal' ou 'protected') d'un objet spécial créé spécifiquement pour le verrouillage est une bonne habitude. Je suis d'accord avec Jon Skeet que permettre le verrouillage sur des objets arbitraires [était une erreur] (http://msmvps.com/blogs/jon_skeet/archive/2008/12/05/redesigning-system-object-java-lang-object.aspx). – Brian

-1

Si l'observateur est le seul auteur et que vos objets ne sont que des lecteurs, un ReaderWriterLock pourrait être meilleur. Assurez-vous de lire la section des remarques.

Questions connexes