Double-vérifier le verrouillage dans .NET
Je suis tombé sur ce l'article discuter pourquoi la double-vérifier le verrouillage de paradigme est cassé en Java. Est le paradigme valable pour .NET (en particulier, C#), si les variables sont déclarées volatile
?
Vous devez vous connecter pour publier un commentaire.
La mise en œuvre de Singleton en C# parle de ce problème dans la troisième version.
Il dit:
L'auteur semble sous-entendre que la double verrouillage est moins susceptibles de travailler que les autres stratégies et ne devraient donc pas être utilisés.
Double-vérifier le verrouillage fonctionne maintenant en Java et C# (la Java du modèle de mémoire changé et c'est l'un des effets). Toutefois, vous devez le faire exactement droit. Si vous gâcher les choses, même légèrement, vous pourriez bien finir par perdre le fil de sécurité.
Comme d'autres réponses ont indiqué, si vous êtes à la mise en œuvre de la le pattern singleton il y a de bien meilleures façons de le faire. Personnellement, si je suis dans une situation où je dois choisir entre le double-vérifier le verrouillage et le "verrouillage de tous les temps" code que j'irais pour le verrouillage de tous les temps jusqu'à ce que j'avais obtenu la preuve que c'était à l'origine un goulot d'étranglement. Quand il s'agit de filetage, un simple et, évidemment-modèle correct vaut beaucoup.
volatile
aide pour JDK5+. Ce sujet .NET? Avolatile
assez pour mettre en œuvre un bon double-vérifier le verrouillage .NET 1.1? (par exemple, concernant l'exemple de la "Troisième version - tentative de fil de sécurité à l'aide de double-vérifier le verrouillage" dans votre article: est-il techniquement "fixe" quandvolatile
mettre surinstance
champ statique?)IsFileOnDiskUpToDate()
et la "nouvelle Singleton" est en faitDownloadContentAndWriteOrUpdateFileOnDisk()
et dans ce cas dois-je besoin d'une "mémoire explicite barrière"? (J'ai été dirigé ici de ma question fermée: stackoverflow.com/questions/5036518/... )// Insure all writes...
.NET 4.0 dispose d'un nouveau type:
Lazy<T>
qui enlève toute préoccupation au sujet d'obtenir le modèle de mal. Il fait partie de la nouvelle Task Parallel Library.Consultez le site web MSDN de Calcul Parallèle Dev Center: http://msdn.microsoft.com/en-us/concurrency/default.aspx
BTW, il y a un backport (je crois que c'est pas pris en charge) pour .NET 3.5 SP1 disponible ici.
Remarque que dans Java (et plus probablement dans .Net ainsi), d'un double contrôle du verrouillage de singleton initialisation est complètement inutile brisés. Étant donné que les classes ne sont pas initialisés jusqu'à ce qu'ils sont d'abord utilisés, le paresseux d'initialisation est déjà atteint par le présent;
À moins que votre classe Singleton contient des trucs comme des constantes qui peuvent être consultés avant qu'une instance du Singleton est utilisé en premier, c'est tout ce que vous devez faire.
Je ne comprends pas pourquoi tous les gens dit que le double-vérifier le verrouillage est mauvais modèle, mais ne pas adapter le code pour qu'il fonctionne correctement. À mon avis, ce code ci-dessous devrait fonctionner parfaitement.
Si quelqu'un pouvait me dire si ce code souffrent du problème mentionné dans Cameron article, s'il vous plaît.
volatile
sur leinstance
membre. (si le code fonctionne est, au moins dans ce cas, n'est pas une question d'opinion, mais une question de fait. Je pense que le fait est que cela ne fonctionne pas, mais j'ai peut-être tort sur ce point).lock
déclaration en C# (Monitor.Enter()
,Monitor.Exit()
) implicitement crée plein de mémoire clôture (albahari.com/threading/part4.aspx). La seule excuse à utiliser volatile en C# par certains est parce que le double contrôle de verrouillage regarde la même chose en Java et en C# afin de ne pas embrouiller les gens. Mon avis est d'utiliserLazy<T>
(msdn.microsoft.com/en-us/library/dd997286(v=vs. 110).aspx)Thread.MemoryBarrier()
avant la cession ferait l'affaire.Le singleton à l'aide boolean ne fonctionne pas. L'ordre des opérations comme on le voit entre les différents threads n'est pas garantie, sauf si vous allez à travers une barrière de mémoire.
En d'autres termes, comme on le voit à partir d'un deuxième thread,
created = true
peut être exécutée avant l'instance= new Singleton();
Je n'arrive pas à comprendre pourquoi il y a un tas de mise en œuvre des schémas sur un double contrôle de verrouillage (apparemment pour contourner compilateur particularités dans différentes langues). L'article de Wikipedia sur ce sujet montre que la méthode naïve et les moyens possibles pour résoudre le problème, mais aucun n'est aussi simple que cela (en C#):
En Java, vous pouvez utiliser synchronisée() à la place de la serrure(), mais c'est un peu la même idée. Si il y a la possible incompatibilité de quand le singleton champ est affectée, alors pourquoi ne pas utiliser un localement étendue variable d'abord et ensuite affecter le singleton champ au dernier moment avant la sortie de la section critique? Ai-je raté quelque chose?
Il y a l'argument par @michael-borgwardt qu'en C# et Java de la statique du champ est initialisé une fois lors de la première utilisation, mais que comportement est spécifique à une langue. Et j'ai utilisé ce modèle fréquemment pour les paresseux de l'initialisation d'une collection de propriété (par exemple, utilisateur.Les Sessions).
_singleton
restenull
jusqu'à la construction de l'objet est fait.” Le compilateur est libre de réorganiser l'ensemble de cette ligne au-dessus defoo.Initialize()
, ou même d'optimiser lesfoo
variable tout à fait. Même si un compilateur est muet, le CPU est intelligent, et peut exécuter la mémoire stocke les faits à l'intérieur defoo.Initialize()
après l'affectation_singleton = foo
. L'article lié à partir de l'original post explique aussi d'autres raisons de ce code ne fait pas ce que vous pouvez penser, il ne.J'ai obtenu une double vérification de verrouillage afin de travailler à l'aide d'un booléen (c'est à dire à l'aide d'une primitive pour éviter les paresseux initialisation):