IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Framework .NET Discussion :

A propos du singleton en dotnet


Sujet :

Framework .NET

  1. #1
    Membre confirmé
    Avatar de teddyalbina
    Homme Profil pro
    Développeur .Net,C++
    Inscrit en
    Janvier 2008
    Messages
    466
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .Net,C++

    Informations forums :
    Inscription : Janvier 2008
    Messages : 466
    Points : 568
    Points
    568
    Par défaut A propos du singleton en dotnet
    Bonsoir,

    J'ai une petite intérrogation à propos de la création de singleton en dotnet.

    Personellement je fais toujours comme cela :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    public class Toto
    {
    private Toto() { }
    private static Toto sInstance;
    private static readonly object sSync = new object();
     
    public static Toto Instance {
    get {
    if (sInstance == null) {
    lock(sSync) {
    if (sInstance == null) {
    sInstance = new Toto();
    }
    }
    }
     
    return sInstance;
    }
    }
    }
    Or au boulot je vois souvent cela :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public class Toto {
     
    private Toto() {
    }
     
    public static Toto Instance = new Toto();
    }

    J'ai effectué quelques tests la seconde méthode semble thread safe, et est aussi plus rapide.

    Qu'en pensez vous ? Avez vous déjà utilisé cette "formulation" pour les singleton en dotnet ?

    Merci
    Viva la viva... en el chorizo de la corida de leon.... (cette phrase n'a aucun sens je sais )

  2. #2
    Invité
    Invité(e)
    Par défaut
    Salut,

    Heu... Je pense que les deux méthodes sont threadsafe vu que dans la 1ère tu utilises le mot clef lock.

    Sinon la méthode que j'utilise pour créer un singleton est le suivant et ressemble énormément à ta deuxième méthode :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    public class Toto 
    {
         public static Toto Instance { get; private set; }
     
         static Toto() 
         {
              Toto.Instance = new Toto();
         }
    }

    Je sais la seule différence est que dans mon cas j'utilise un constructeur statique pour instancier le singleton mais ça le mérite d'être lisible. Je préfère toujours instancier les membres statiques dans un ce type de constructeur pour plus de lisibilité .

    EDIT : Une erreur que je viens de voir dans ton code, dans la 2ème méthode, est que ce n'est un singleton que t'as mis en place vu que l'instance qui est censée être unique est modifiable . Tu dois déclarer l'instance en tant que propriété avec un setter en mode private comme je l'ai fait dans mon code et justement utilisé un constructeur statique pour instancier le singleton. .
    Dernière modification par Invité ; 22/11/2011 à 22h15.

  3. #3
    Membre émérite Avatar de meziantou
    Homme Profil pro
    Ingénieur R&D
    Inscrit en
    Avril 2010
    Messages
    1 223
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur R&D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 223
    Points : 2 439
    Points
    2 439
    Par défaut
    Pour la première implémentation pense à utiliser le mot clé volatile ou Thread.MemoryBarrier

    http://www.codeproject.com/KB/tips/MemoryBarrier.aspx

    http://msdn.microsoft.com/en-us/library/ff650316.aspx

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    La seconde méthode est meilleure dans le sens où elle est intrinsèquement thread-safe, sans avoir à faire un lock manuel, car l'initialisation d'un type est toujours thread-safe (c'est géré par le CLR). Par contre tu devrais rendre ton champ readonly...

    D'une manière générale, je pense qu'il vaut mieux garder l'implémentation la plus simple possible, ça évite de faire des petites erreur bêtes... donc exit les lock, MemoryBarrier, etc

    En général j'utilise cette technique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public class MonSingleton
    {
        private MonSingleton() { }
     
        private static readonly MonSingleton _instance = new MonSingleton();
        public static MonSingleton Instance { get { return _instance; } }
    }
    L'inconvénient de cette technique est qu'elle n'est pas "lazy" : dans certains cas tu peux vouloir que l'instance soit créée le plus tard possible, lors de sa première utilisation (ce que fait ta première technique)

    Si tu utilises .NET 4, il y a une autre approche, lazy et thread-safe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public class MonSingleton
    {
        private MonSingleton() { }
     
        private static readonly Lazy<MonSingleton> _lazyInstance = new Lazy<MonSingleton>(() => new MonSingleton());
        public static MonSingleton Instance { get { return _lazyInstance.Value; } }
    }
    C'est la classe Lazy qui fait tout le boulot

    Pour finir, cet article décrit différentes approches pour implémenter le pattern Singleton en C#

  5. #5
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut singleton
    bonjour teddyalbina

    Pour completer un peu:
    1/ constructeur prive : empeche l'instanciation et l'heritage.
    Sinon le compilateur en genere un par default public

    2/ Ne doit pas implementer :
    - ICloneable:la creation d'une instance totalement sous controle de GetInstance.
    /- Serializable sinon une copie peut etre cree et transmise via reseau car un objet serializable supporte le remotecall.

    bonne code............

  6. #6
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    @Teddyalbina
    Comme dit plus haut l'initialisation en ligne (via un constructeur statique en réalité) du champ statique est thread-safe pas de souci.

    Si en revanche on veut une approche paresseuse, on peut effectivement utiliser Lazy ou alors, plutôt qu'un verrou comme tu l'avais fait, s'appuyer sur un compare-and-swap atomique. Au cas où tu ne connaîtrais pas (et le fait que tu aies utilisé un verrour me fait songer que ce n'est pas le cas), voilà le principe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if (sInstance == null)
    {
       Interlocked.CompareExchange(ref sInstance, new Toto(), null)
    }
    return sInstance
    Interlocked.CompareExchange(ref field, newValue, oldValue) équivaut au code suivant exécuté de façon atomique, c'est à dire sans qu'un autre thread ne puisse fausser l'opération. Cela économise un verrou.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if (field == oldValue) 
    {
       field = newValue;
       return oldValue;
    }
    return field;
    Dans le code donné au tout début, je n'ai utilisé un if (sInstance == null) que pour éviter qu'on instancie à chaque fois Toto. Il se peut toujours qu'au début, si deux threads venaient à déclencher le code en même temps, Toto ait été instancié deux fois mais, au final, sInstance n'aura été assigné qu'une seule fois et les deux appels renverront tous deux la même instance : celle qui a été assignée. Par la suite, le if évite qu'on ne réinstancie Toto.

    Interlocked.CompareExchange appelle en fait une instruction spéciale du processeur pour garantir l'atomicité de l'opération. C'est grâce à cette opération que l'on peut réaliser des structures concurrentes sans verrou. Interlocked fournit aussi une incrémentation/décrémentation atomique.

    Enfin, note qu'un champ doit avoir été marqué volatile pour être utilisé avec Interlocked. Un warning sera émis mais ce n'est qu'un bug dans ce cas précis, on peut le désactiver grâce à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #pragma warning disable 0420
    #pragma warning restore 0420

Discussions similaires

  1. question de débutant à propos de dotnet
    Par Kapha dans le forum Débuter
    Réponses: 1
    Dernier message: 08/08/2007, 19h53
  2. A propos des singletons
    Par zenux dans le forum C++
    Réponses: 1
    Dernier message: 19/11/2006, 09h30
  3. A propos des modèles d'objet (avec sources)
    Par DevX dans le forum C++Builder
    Réponses: 14
    Dernier message: 01/12/2002, 12h22
  4. Fonctionnement de la compression DivX
    Par Rodrigue dans le forum Algorithmes et structures de données
    Réponses: 2
    Dernier message: 20/09/2002, 14h10
  5. A propos du composant DBGrid
    Par _Rico_ dans le forum C++Builder
    Réponses: 2
    Dernier message: 24/07/2002, 09h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo