Menu
Coddy logo textTech

Singleton Thread-Safe

Fait partie de la section Programmation Orientée Objet du Journey C# de Coddy. Leçon 52 sur 70.

Le pattern Singleton garantit qu'une classe n'a qu'une seule instance dans toute votre application et fournit un point d'accès global à celle-ci. Ceci est utile pour gérer des ressources partagées telles que les paramètres de configuration, les services de journalisation ou les connexions aux bases de données.

Un Singleton de base utilise un constructeur privé pour empêcher l’instanciation externe et une propriété statique pour fournir un accès :

public class Logger
{
    private static Logger _instance;
    private static readonly object _lock = new object();
    
    private Logger() { }  // Constructeur privé
    
    public static Logger Instance
    {
        get
        {
            lock (_lock)
            {
                if (_instance == null)
                    _instance = new Logger();
                return _instance;
            }
        }
    }
    
    public void Log(string message) => Console.WriteLine(message);
}

L’instruction lock garantit la sécurité des threads : si plusieurs threads tentent d’accéder simultanément à Instance, un seul peut entrer dans la section critique à la fois. Sans cela, deux threads pourraient tous deux voir _instance comme étant null et créer des instances distinctes.

C# offre une approche plus simple et thread-safe grâce à l’initialisation statique :

public class Logger
{
    private static readonly Logger _instance = new Logger();
    
    private Logger() { }
    
    public static Logger Instance => _instance;
    
    public void Log(string message) => Console.WriteLine(message);
}

Cette version est sûre dans un environnement multithread, car le CLR garantit que l'initialisation d'un champ statique ne se produit qu'une seule fois. Les deux approches garantissent que vous obtenez toujours la même instance :

Logger.Instance.Log("First call");
Logger.Instance.Log("Same instance");
challenge icon

Défi

Facile

Construisons un gestionnaire de configuration thread-safe à l’aide du modèle Singleton. Dans les applications réelles, les paramètres de configuration doivent être accessibles dans l’ensemble du programme tout en garantissant qu’une seule instance existe : c’est un cas d’utilisation idéal pour Singleton.

Vous allez organiser votre code dans deux fichiers :

  • ConfigManager.cs : créez une classe ConfigManager dans l’espace de noms Configuration qui implémente le modèle Singleton. Votre gestionnaire de configuration doit :
    • posséder un champ statique privé pour contenir l’unique instance
    • utiliser un constructeur privé afin d’empêcher toute instanciation externe
    • fournir une propriété statique Instance qui renvoie l’unique instance (utilisez l’approche d’initialisation statique plus simple pour garantir la sécurité des threads)
    • inclure un champ privé de type string _appName initialisé à "MyApp"
    • posséder une méthode SetAppName(string name) pour mettre à jour le nom de l’application
    • posséder une méthode GetAppName() qui renvoie le nom actuel de l’application
  • Program.cs : dans votre fichier principal, démontrez que le Singleton fonctionne correctement en accédant plusieurs fois à l’instance et en montrant que les modifications sont conservées dans toutes les références.

Vous recevrez une entrée :

  • Un nouveau nom d’application à définir (par exemple, ProductionServer)

Dans votre programme :

  1. récupérez l’instance de ConfigManager et affichez le nom d’application par défaut
  2. récupérez à nouveau l’instance (dans une variable différente) et utilisez-la pour définir le nouveau nom d’application fourni en entrée
  3. récupérez l’instance une troisième fois et affichez le nom de l’application afin de prouver que toutes les références partagent les mêmes données

Par exemple, si l’entrée est ProductionServer, la sortie doit être :

MyApp
ProductionServer

Cela démontre l’avantage principal du Singleton : quel que soit le nombre de fois où vous accédez à Instance, vous obtenez toujours le même objet avec un état partagé. L’approche d’initialisation statique garantit la sécurité des threads, car le CLR veille à ce que le champ statique soit initialisé une seule fois, même si plusieurs threads y accèdent simultanément.

Essayez vous-même

using System;
using Configuration;

class Program
{
    public static void Main(string[] args)
    {
        // Lire la saisie - le nouveau nom de l'application
        string newAppName = Console.ReadLine();
        
        // TODO: Obtenir l'instance de ConfigManager et afficher le nom de l'application par défaut
        
        // TODO: Obtenir à nouveau l'instance (dans une variable différente) et l'utiliser pour définir le nouveau nom de l'application
        
        // TODO: Obtenir l'instance une troisième fois et afficher le nom de l'application pour prouver que toutes les références partagent les mêmes données
    }
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet

Entraînez-vous par vous-même : Compilateur C# en ligne