Est le C# static constructeur thread-safe?
En d'autres termes, est-ce Singleton mise en œuvre thread-safe:
public class Singleton
{
private static Singleton instance;
private Singleton() { }
static Singleton()
{
instance = new Singleton();
}
public static Singleton Instance
{
get { return instance; }
}
}
Il n'est pas thread-safe. Supposons que plusieurs threads veulent obtenir la propriété
Les autres threads ne sont pas verrouillées. De ma propre expérience, je me suis méchant erreurs à cause de cela. La garantie est que seul le poing thread va démarrer l'initialiseur statique, ou d'un constructeur, mais alors les autres threads essayez d'utiliser une méthode statique, même si le processus de construction n'a pas fini.
Cet exemple (source codé dans l'URL) ne peut pas reproduire le problème que vous décrivez. Peut-être que ça dépend de la version du CLR-vous?
Merci de prendre votre temps. Pouvez-vous s'il vous plaît expliquez-moi pourquoi ici le domaine est surchargé?
Avec ce code, dans le haut-cas
Instance
à la fois. L'un des threads sera racontée à la première exécution de l'initialiseur de type (aussi connu comme le constructeur statique). Pendant ce temps tous les autres threads envie de lire la Instance
de la propriété, sera verrouillé jusqu'à ce que l'initialiseur de type fini. Seulement après que le champ de l'initialiseur a conclu, sera threads être autorisés à obtenir le Instance
valeur. De sorte que personne ne peut voir Instance
être null
.Les autres threads ne sont pas verrouillées. De ma propre expérience, je me suis méchant erreurs à cause de cela. La garantie est que seul le poing thread va démarrer l'initialiseur statique, ou d'un constructeur, mais alors les autres threads essayez d'utiliser une méthode statique, même si le processus de construction n'a pas fini.
Cet exemple (source codé dans l'URL) ne peut pas reproduire le problème que vous décrivez. Peut-être que ça dépend de la version du CLR-vous?
Merci de prendre votre temps. Pouvez-vous s'il vous plaît expliquez-moi pourquoi ici le domaine est surchargé?
Avec ce code, dans le haut-cas
X
finit par être -1
même sans filetage. Ce n'est pas un thread de problème de sécurité. Au lieu de cela, l'initialiseur x = -1
s'exécute en premier (il est sur une ancienne ligne dans le code, un numéro de ligne inférieur). Puis l'initialiseur X = GetX()
fonctionne, ce qui rend les majuscules X
égal à -1
. Et puis le "explicite" constructeur statique, l'initialiseur de type static C() { ... }
pistes, qui ne varie que de bas-de-casse x
. Alors, après tout cela, le Main
de la méthode (ou Other
méthode) peut aller sur et lire en majuscules X
. Sa valeur sera -1
, même avec un seul thread.OriginalL'auteur urini | 2008-08-10
Vous devez vous connecter pour publier un commentaire.
Constructeurs statiques sont garantis pour être exécuté qu'une seule fois par domaine d'application, avant que toutes les instances d'une classe sont créés ou tous les membres statiques sont accessibles. http://msdn.microsoft.com/en-us/library/aa645612.aspx
La mise en œuvre montré est thread-safe pour la construction initiale, qui est, sans aucun blocage ou null examen est requis pour la construction de l'objet Singleton. Toutefois, cela ne signifie pas que toute utilisation de l'instance sera synchronisée. Il existe une variété de façons que cela peut être fait; je vous ai montré ci-dessous.
D'accord, mais j'irais plus loin. Si votre singleton est immuable, à l'aide d'un singleton est exagéré. Il suffit de définir des constantes. En fin de compte, à l'aide d'un singleton convenablement, il faut que les développeurs savent ce qu'ils font. Aussi fragile que cette mise en œuvre est, il est encore meilleur que celui de la question de savoir où ces erreurs manifestes au hasard, plutôt que comme une évidence inédits mutex.
Une façon d'atténuer la fragilité de la méthode Release() est à utiliser une autre classe avec IDisposable en tant que gestionnaire de synchronisation. Lorsque vous avez acquis le singleton, vous obtenez le gestionnaire et peut mettre le code nécessitant le singleton en utilisant le bloc de gérer la libération.
Pour les autres personnes qui pourraient être déclenchés par ceci: Tout champ statique membres avec les initialiseurs sont initialisés avant le constructeur statique est appelé.
La réponse de ces journées est d'utiliser
Lazy<T>
- toute personne qui utilise le code que j'ai posté est de faire le mal (et honnêtement, il n'était pas bon de commencer avec - 5-ans-ans-moi, n'était pas aussi bon à ce genre de choses que le courant-moi 🙂 ).OriginalL'auteur Zooba
Bien que toutes ces réponses sont à donner la même réponse générale, il y a un problème.
Rappelez-vous que toutes les dérivations d'une classe générique sont compilés en tant que types individuels. Donc faire preuve de prudence lors de la mise en œuvre de constructeurs statiques pour les types génériques.
EDIT:
Voici la démonstration:
Dans la console:
Je pense que c'est le point que j'essaie de faire. Les types génériques sont compilés à différents types sur la base de laquelle les paramètres génériques sont utilisés, de sorte que le constructeur statique peut être appelée plusieurs fois.
C'est juste quand T est de type valeur, par type de référence T un type générique serait généré
Pas Vrai... Voir mon Edit
Intéressant, mais vraiment statique cosntructor appelé pour tous les types, juste essayé pour plusieurs types de référence
OriginalL'auteur Brian Rudolph
À l'aide d'un constructeur statique en fait est des threads. Le constructeur statique est garanti pour être exécutée qu'une seule fois.
À partir de la spécification du langage C#http://msdn.microsoft.com/en-us/library/aa645612(SV.71).aspx:
Donc oui, vous pouvez avoir confiance que votre singleton sera correctement instancié.
Zooba fait un excellent point (et 15 secondes avant moi, aussi!) que le constructeur statique ne garantit pas thread-safe accès partagé à la singleton. Qui devront être traitées d'une autre manière.
OriginalL'auteur Derek Park
Voici la Cliffnotes version de la ci-dessus page MSDN sur c# singleton:
Utiliser le modèle suivant, toujours, vous ne pouvez pas vous tromper:
Au-delà de l'évident singleton fonctionnalités, il vous donne ces deux choses gratuitement (dans le respect de singleton en c++):
Qu'est-C++ ont à voir avec cela?
OriginalL'auteur Jay Juch
Constructeurs statiques sont garantis à feu qu'une seule fois par le Domaine de l'Application de sorte que votre approche devrait être OK. Cependant, il est fonctionnellement différent de la plus concise, en ligne version:
La sécurité des threads est plus un problème lorsque vous êtes paresseusement initialisation de choses.
Derek, je suis familier avec le beforefieldinit "optimisation" mais, personnellement, je n'ai jamais de souci.
lien de travail pour @DerekPark commentaire: csharpindepth.com/Articles/General/Beforefieldinit.aspx. Ce lien semble être obsolète: ondotnet.com/pub/a/dotnet/2003/07/07/staticxtor.html
OriginalL'auteur Andrew Peters
La Common Language Infrastructure spécification garantit que "l'un initialiseur de type court à exactement une fois pour un type donné, sauf s'il est explicitement appelé par le code de l'utilisateur." (Section 9.5.3.1.) Donc, sauf si vous avez quelques déjanté IL le lâche appel Singleton::.cctor directement (peu probable) votre constructeur statique sera exécuté qu'une seule fois avant le Singleton de type est utilisé, une seule instance du Singleton sera créé, et votre Exemple de la propriété est thread-safe.
Noter que si Singleton constructeur accède à la propriété d'Instance (même indirectement), alors la propriété d'Instance sera nulle. Le meilleur que vous pouvez faire est de détecter le moment où cela se produit et lancer une exception, le contrôle de cette instance est non-nulle dans la propriété de l'accesseur. Après votre constructeur statique complète la propriété d'Instance sera non nulle.
Comme Zoomba réponse points, vous aurez besoin de faire un Singleton de sécurité pour l'accès à partir de plusieurs threads, ou de mettre en œuvre un mécanisme de verrouillage autour de l'aide de l'instance du singleton.
OriginalL'auteur Dominic Cooney
Le constructeur statique sera finition de course avant aucun thread n'est autorisé à accéder à la classe.
Le code ci-dessus a produit les résultats ci-dessous.
Même si le constructeur statique a fallu beaucoup de temps pour courir, les autres threads s'arrêta et attendit. Tous les threads de lire la valeur de _x fixé à la partie inférieure du constructeur statique.
OriginalL'auteur Trade-Ideas Philip
Juste pour être pédant, mais il n'y a pas une telle chose comme un constructeur statique, mais plutôt de type statique initialiseurs, voici une petite démo de cyclique constructeur statique de dépendance qui illustre ce point.
OriginalL'auteur Florian Doyon
Constructeur statique est garanti d'être thread-safe.
Aussi, voir la discussion sur le Singleton à DeveloperZen:
http://www.developerzen.com/2007/07/15/whats-wrong-with-this-code-1-discussion/
OriginalL'auteur Eran Kampf
Bien que d'autres réponses sont la plupart du temps correct, il y a encore un autre inconvénient avec les constructeurs statiques.
Conformément à l'article II.10.5.3.3 Courses et de blocages de la ECMA-335 Langue Commune
L'Infrastructure
Le code ci-dessous dans une impasse
Auteur Original est Igor Ostrovsky, voir son post ici.
OriginalL'auteur oleksii