C# Singleton thread-safe
J'ai une classe singleton similaire à ce
public class Singleton
{
private static Singleton m_instance;
private Timer m_timer;
private static List<CustomObject> m_cacheObjects;
private Singleton()
{
m_cacheObjects = new List<CustomObject>();
m_timer= new Timer(MyTimerCallBack,
null,
TimeSpan.FromSeconds(60),
TimeSpan.FromSeconds(60));
}
public static Singleton Instance
{
get
{
if (m_instance == null)
{
m_instance = new Singleton();
}
return m_instance;
}
}
private void MyTimerCallBack(object state)
{
//******** Update the list by interval here ******************
m_cacheObjects = UpdateTheList();
}
public void CallMe()
{
foreach (CustomObject obj in m_cacheObjects)
{
//do something here based on obj
//The question is, does the m_cacheObjects is thread safe??
//what happen if the m_cacheObjects is changed
//during the loop interation?
}
}
}
La CallMe méthode sera appelée par le service web:
[WebMethod]
public void CallMeWebService()
{
Singleton.Instance.CallMe();
}
Les questions:
1) Est la m_cacheObjects est thread-safe? qu'advient-il si le m_cacheObjects est changé(en raison de la minuterie) au cours de la boucle d'interaction (dans le CallMe() )?
2) Est un nouveau thread est créé lorsque le Webservice CallMeWebService() est appelée?
1)un) N, 1)b) Vous ne pouvez pas être sûr, 2) Oui
Je vais suivre le ci-dessous les réponses pour faire l'initialisation statique d'être thread-safe.
Maintenant j'ai plus de souci à propos de la liste statique m_cacheObjects. Je implicitement pause (mode debug)dans la boucle foreach et attendre que la minuterie à les tiques et modifier le m_cacheObjects liste, on peut supposer que la boucle foreach va échouer en raison de la modification de la liste, mais il continuer la boucle sans exception. Est-ce normal?
Juste pour info avec tous les verrouillage: Si
Je vais suivre le ci-dessous les réponses pour faire l'initialisation statique d'être thread-safe.
Maintenant j'ai plus de souci à propos de la liste statique m_cacheObjects. Je implicitement pause (mode debug)dans la boucle foreach et attendre que la minuterie à les tiques et modifier le m_cacheObjects liste, on peut supposer que la boucle foreach va échouer en raison de la modification de la liste, mais il continuer la boucle sans exception. Est-ce normal?
Juste pour info avec tous les verrouillage: Si
m_cacheObjects
est modifié par MyTimerCallBack
(j'.e toutes les autres méthodes que l'accès m_cacheObjects
sont read-only
, ça serait beaucoup plus simple de juste lock
m_cacheObjects
pendant MyTimerCallBack
qui est appelé une fois en une minute, plutôt qu'à plusieurs reprises le verrouillage et le déverrouillage à chaque fois que quelqu'un appelle la read-only
méthodes. Au meilleur de ma connaissance, le verrouillage de lecture n'est pas indispensable, que lorsque l'état de la collection pourrait changer.OriginalL'auteur user1553857 | 2012-07-26
Vous devez vous connecter pour publier un commentaire.
1: Non, une liste statique n'est pas automatiquement thread-safe, vous devez protéger
m_cacheObjects
manuellement2: C'est un détail d'implémentation; à première vue, il ressemble à il expose lui-même comme une méthode de synchronisation, mais comment qu'il ne soit entièrement à elle
En fait, votre initialisation statique n'est pas thread-safe, j'ai pu la force brute d'un scénario où deux
Singleton
instances ont été utilisés. Il faudrait répétition pour le produire, mais qu'il allait se passer.Franchement, sauf si vous avez une très bonne raison de ne pas, le plus simple, mais la plus sûre pattern singleton est tout simplement:
Lazy<>
?remarque je l'ai mentionné plus "simple". Pour être franc, les situations qui ont besoin d'un initialisées singleton sont très rares; a: singletons doivent être rares, b: vous devez savoir que
Singleton
a été coûteux à créer, et c: vous aurez besoin de savoir qu'il y a des choses utiles qui peut être fait sans qui en ont besoin. Dans ce cas, je pense qu'il ne parvient pas réellement tous les 3 critères.Manuellement, voulez-vous dire en utilisant le verrouillage de mot-clé ou quelque chose d'autre?
oui je suis tout à fait dire "le dispositif de verrouillage de mot-clé ou quelque chose d'autre" ;p évidemment
lock
serait l'approche la plus simple (et la simplicité compte pour beaucoup), mais il ya beaucoup de façons, il pourrait en être fait.OriginalL'auteur Marc Gravell
Je vous suggère de vous avoir alis sur Jon Skeets article sur la façon de créer de thread safe singletons plus à http://csharpindepth.com/Articles/General/Singleton.aspx
OriginalL'auteur Grhm
Expliquer:
[Attribut Methodimpl(MethodImplOptions.Synchronisé)] Ce sera de dire au compilateur que l'accès à une "Instance" est "Synchronisée", de sorte que le système de prendre soin sur les appels à ce Paramètre.
C'est Thread-Safe.
EDIT:
(Aussi, le "Lock()" exemples ne sont pas en sécurité! Coz, u pouvez désactiver le fil de Sécurité avec le "Moniteur.Sortie(Singleton);")
OriginalL'auteur k1ll3r8e
C'est plutôt une bonne ressource sur la manière d'implémenter le pattern singleton dans un thread de façon sécuritaire: http://msdn.microsoft.com/en-us/library/ff650316.aspx
Ce simplement fait en sorte qu'il n'y aura jamais plus d'une instance. Vous devez également appliquer le verrouillage de votre méthode personnalisée.
OriginalL'auteur Mithon
Il n'est pas thread-safe.
Je crois que je voudrais utiliser une de verrouillage dans les deux 'MyTimerCallBack" et "CallMe" méthodes
OriginalL'auteur Luis Filipe
1) Non,
m_cacheObjects
n'est pas thread-safe.2) Oui, un nouveau sujet sera créé (eh bien, il peut ne pas être nouveau fil de discussion, mais plutôt de fil prise en charge de thread pool).
Vous aurez besoin pour protéger
m_cacheObjects
aveclock
déclaration. Aussi, dans la méthode CallMe je vous recommande de créer une copie locale dem_cacheObjects
:Nouvelle méthode CallMe:
Et mis à jour
MyTimerCallBack
méthode:Et merci également de mettre en œuvre thread-safe Singleton (lire les autres réponses pour plus de détails).
Seul
lock
déclaration n'a pas de sens. En utilisantlock
dansMyTimerCallback
vous pouvez être sûr queCallMe
va attendre jusqu'à ce que MyTimerCallback complète. Et vice versa - lock enCallMe
permet de s'assurer quem_cacheObjects
ne sera pas mis à jour jusqu'à ce que ça va être copié sur unlocalCopy
.OriginalL'auteur Alexander