Est-il possible d'utiliser une chaîne comme un verrouillage de l'objet?
J'ai besoin de faire une section critique dans un domaine sur la base d'un ensemble fini de chaînes de caractères. Je veux la serrure pour être partagé pour la même instance de chaîne, (un peu comme Chaîne de caractères.Stagiaire approche).
Je suis d'examiner la mise en œuvre suivants:
public class Foo
{
private readonly string _s;
private static readonly HashSet<string> _locks = new HashSet<string>();
public Foo(string s)
{
_s = s;
_locks.Add(s);
}
public void LockMethod()
{
lock(_locks.Single(l => l == _s))
{
...
}
}
}
Sont là des problèmes avec cette approche? Est-il OK pour verrou sur un objet de type string de cette façon, et il n'existe aucun fil des questions de sécurité à l'aide de la HashSet<string>
?
Est-il mieux, par exemple, créer un Dictionary<string, object>
qui crée un nouvel objet de verrouillage pour chaque instance de chaîne?
Final De Mise En Œuvre
Sur la base des suggestions, je suis allé avec la mise en œuvre suivants:
public class Foo
{
private readonly string _s;
private static readonly ConcurrentDictionary<string, object> _locks = new ConcurrentDictionary<string, object>();
public Foo(string s)
{
_s = s;
}
public void LockMethod()
{
lock(_locks.GetOrAdd(_s, _ => new object()))
{
...
}
}
}
- Je les bizarreries de l'aide d'un
string
comme le verrouillage de la cible dans ma réponse ici. - Puis-je suggérer un léger changement? de verrouillage(_locks.GetOrAdd(_s, s => new object())) Ce qui le rend si vous ne créez un objet par chaîne, au lieu d'en créer un à chaque fois que vous appelez LockMethod().
- Concernant les problèmes d'inégalité des instances de chaîne mentionné à la fois par le JonSkeet et BrianGideon, je vous suggère de l'aide
lock(_locks.GetOrAdd(String.Intern(_s), s => new object()))
, bien que le stage peut encore être désactivé viaCompilationRelaxations.NoStringInterning
et puis cela ne fonctionne pas, soit. Peut-être, à l'aide de la chaîne dehashcode
comme un élément clé dans le dictionnaire serait de l'aide ici?! - un stage est un problème lorsque vous le verrouillage d'une chaîne de caractères (quelqu'un d'autre peut le verrou sur la même interné instance de chaîne). Ici, nous verrou sur une nouvelle instance de l'objet, et non pas sur la chaîne de l'instance. Personne d'autre n'a accès à cette nouvelle instance de l'objet.
Vous devez vous connecter pour publier un commentaire.
De verrouillage sur les cordes est découragé, la raison principale est que (en raison de la chaîne de formation) ou un autre code de verrouillage sur la même instance de chaîne, sans le savoir ce. La création d'un potentiel pour des situations de blocage.
C'est sans doute farfelue scénario dans la plupart des situations concrètes. C'est plus une règle générale pour les bibliothèques.
Mais d'un autre côté, qu'est-ce que les avantages perçus de chaînes?
Donc, point par point:
Oui, mais surtout théorique.
La
HashSet<>
n'est pas impliqué dans le fil de sécurité tant que le fils seulement de lire en même temps.Oui. Juste pour être sur le côté sécuritaire. Dans un système plus large, l'objectif principal pour éviter le blocage est de garder le verrouillage des objets locaux et privée que possible. Seule une quantité limitée de code doit être en mesure d'y accéder.
Je dirais que c'est une très mauvaise idée, personnellement. Ce n'est pas ce que les chaînes sont pour.
(Personnellement je n'aime pas le fait que chaque objet a un moniteur en premier lieu, mais c'est un peu une autre préoccupation.)
Si vous souhaitez un objet qui représente un verrou qui peut être partagé entre les différentes instances, pourquoi ne pas créer un type spécifique pour cela? Vous pouvez donné le verrouillage d'un nom assez facilement pour des fins de diagnostic, mais le verrouillage est vraiment pas le but d'une chaîne. Quelque chose comme ceci:
Compte tenu de la façon dont les chaînes sont parfois internés et parfois pas (dans un sens qui peut parfois être difficiles à discerner, par simple inspection), vous pourriez facilement vous retrouver avec accidentellement verrous partagés où vous n'avez pas l'intention d'eux.
ConcurrentDictionary<string, object>
pour remplacer leHashSet<string>
qui crée un nouvel objet de verrouillage pour chaque chaîne de être une bonne approche?Lock
classe n'aurais pas besoin supplémentaire membres, à moins que vous vouliez lui donner unname
propriété (et remplacerToString
) - le point est que ce serait extrêmement clair pour toute personne lisant le code de ce qu'est une variable de typeLock
était pour.Lock
type de la réponse.Lock
objets auraient encore besoin d'être stockées de manière statique, quelque part, donc si je comprends bien l'avantage de ce nouveau type est assez bien pour des raisons de lisibilité.this.name = String.Intern(name);
et 2) l'utilisation par exemple d'un const préfixe pour le nomthis.name = String.Intern(Prefix + name);
être une amélioration pour lesLock
classe?Le verrouillage des chaînes peut être problématique, parce que les internés chaînes sont essentiellement mondial.
Interné chaînes sont par processus, de sorte qu'ils sont encore partagés entre les différents domaines d'application. En va de même pour les objets de type (afin de ne pas bloquer sur typeof(x)) soit.
J'ai eu un problème similaire il n'ya pas longtemps, où j'ai été la recherche d'un bon moyen de verrouiller une section de code basé sur une chaîne de valeur. Voici ce que nous avons en place à l'heure actuelle, qui résout le problème de l'internement des cordes et a la granularité nous voulons.
L'idée principale est de maintenir un statique ConcurrentDictionary de synchronisation des objets avec une chaîne de clé. Lorsqu'un thread entre dans la méthode, il établit immédiatement une serrure et les tentatives d'ajout de la synchronisation de l'objet de la simultanées dictionnaire. Si nous pouvons ajouter à la simultanées dictionnaire, cela signifie qu'aucun autre thread avoir un verrou basé sur notre chaîne de clé et nous pouvons continuer notre travail. Sinon, nous allons utiliser la synchronisation de l'objet de la simultanées dictionnaire d'établir un deuxième verrou, qui va attendre que le thread en cours d'exécution à la fin du traitement. Lorsque le second verrou est libéré, nous pouvons tenter d'ajouter le thread en cours de synchronisation de l'objet dans le dictionnaire de nouveau.
Un mot de prudence: les fils ne sont pas mis en file d'attente - si plusieurs threads avec les mêmes clés de la chaîne sont en concurrence simultanément pour une serrure, il n'y a aucune garantie quant à l'ordre dans lequel ils seront traités.
Hésitez pas à critiquer si vous pensez que j'ai oublié quelque chose.