Menu
Coddy logo textTech

Thread-Safe Singleton

Coddy'nin C# Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 52 / 70.

Singleton deseni, bir sınıfın uygulamanız boyunca yalnızca bir örneğe sahip olmasını sağlar ve bu örneğe küresel bir erişim noktası sunar. Bu; yapılandırma ayarları, günlükleme (logging) servisleri veya veritabanı bağlantıları gibi paylaşılan kaynakları yönetmek için kullanışlıdır.

Temel bir Singleton, harici örneklemeyi önlemek için özel bir yapıcı (private constructor) ve erişim sağlamak için statik bir özellik kullanır:

public class Logger
{
    private static Logger _instance;
    private static readonly object _lock = new object();
    
    private Logger() { }  // Özel yapıcı
    
    public static Logger Instance
    {
        get
        {
            lock (_lock)
            {
                if (_instance == null)
                    _instance = new Logger();
                return _instance;
            }
        }
    }
    
    public void Log(string message) => Console.WriteLine(message);
}

lock ifadesi iş parçacığı güvenliğini (thread safety) sağlar; birden fazla iş parçacığı Instance özelliğine aynı anda erişmeye çalışırsa, kritik bölüme aynı anda yalnızca biri girebilir. Bu olmadan, iki iş parçacığı da _instance değişkenini null olarak görebilir ve ayrı örnekler oluşturabilir.

C#, statik başlatma (static initialization) kullanarak daha basit, iş parçacığı açısından güvenli (thread-safe) bir yaklaşım sunar:

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);
}

Bu sürüm iş parçacığı açısından güvenlidir (thread-safe) çünkü CLR, statik alan başlatma işleminin yalnızca bir kez gerçekleşmesini garanti eder. Her iki yaklaşım da her zaman aynı örneği almanızı sağlar:

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

Görev

Kolay

Singleton desenini kullanarak iş parçacığı güvenli (thread-safe) bir yapılandırma yöneticisi oluşturalım. Gerçek uygulamalarda, yapılandırma ayarlarının tüm program boyunca erişilebilir olması gerekirken yalnızca bir örneğin (instance) var olduğundan emin olunmalıdır; bu, Singleton için mükemmel bir kullanım durumudur.

Kodunuzu iki dosya halinde düzenleyeceksiniz:

  • ConfigManager.cs: Configuration ad alanı (namespace) içinde Singleton desenini uygulayan bir ConfigManager sınıfı oluşturun. Yapılandırma yöneticiniz şunları yapmalıdır:
    • Tek örneği tutmak için özel bir statik (private static) alana sahip olmalıdır
    • Dışarıdan örnek oluşturulmasını önlemek için özel bir yapıcı (private constructor) kullanmalıdır
    • Tek örneği döndüren statik bir Instance özelliği sağlamalıdır (iş parçacığı güvenliği için daha basit olan statik başlatma yaklaşımını kullanın)
    • "MyApp" olarak başlatılmış özel bir dize alanı olan _appName içermelidir
    • Uygulama adını güncellemek için bir SetAppName(string name) metoduna sahip olmalıdır
    • Mevcut uygulama adını döndüren bir GetAppName() metoduna sahip olmalıdır
  • Program.cs: Ana dosyanızda, örneğe birden çok kez erişerek ve değişikliklerin tüm referanslarda kalıcı olduğunu göstererek Singleton'ın doğru çalıştığını kanıtlayın.

Bir girdi alacaksınız:

  • Ayarlanacak yeni bir uygulama adı (örneğin, ProductionServer)

Programınızda:

  1. ConfigManager örneğini alın ve varsayılan uygulama adını yazdırın
  2. Örneği tekrar alın (farklı bir değişkene) ve girdiden gelen yeni uygulama adını ayarlamak için kullanın
  3. Örneği üçüncü kez alın ve tüm referansların aynı veriyi paylaştığını kanıtlamak için uygulama adını yazdırın

Örneğin, girdi ProductionServer ise, çıktı şu şekilde olmalıdır:

MyApp
ProductionServer

Bu, Singleton'ın temel faydasını gösterir - Instance özelliğine kaç kez erişirseniz erişin, her zaman paylaşılan duruma sahip aynı nesneyi alırsınız. Statik başlatma yaklaşımı iş parçacığı güvenliğini garanti eder çünkü CLR, birden fazla iş parçacığı aynı anda erişse bile statik alanın yalnızca bir kez başlatılmasını sağlar.

Kopya kağıdı

Singleton deseni, bir sınıfın uygulamanız boyunca yalnızca bir örneğe sahip olmasını sağlar ve ona küresel bir erişim noktası sunar.

İş parçacığı güvenliği (thread safety) için açık kilitleme kullanan temel Singleton:

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

lock ifadesi, aynı anda yalnızca bir iş parçacığının kritik bölüme girmesine izin vererek iş parçacığı güvenliğini sağlar.

Statik başlatma (static initialization) kullanan daha basit, iş parçacığı açısından güvenli Singleton:

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);
}

Bu yaklaşım iş parçacığı açısından güvenlidir çünkü CLR, statik alan başlatmanın yalnızca bir kez gerçekleşmesini garanti eder.

Kullanım - her zaman aynı örneği döndürür:

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

Kendin dene

using System;
using Configuration;

class Program
{
    public static void Main(string[] args)
    {
        // Girdiyi oku - yeni uygulama adı
        string newAppName = Console.ReadLine();
        
        // TODO: ConfigManager örneğini al ve varsayılan uygulama adını yazdır
        
        // TODO: Örneği tekrar al (farklı bir değişkene) ve yeni uygulama adını ayarlamak için kullan
        
        // TODO: Örneği üçüncü kez al ve tüm referansların aynı veriyi paylaştığını kanıtlamak için uygulama adını yazdır
    }
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler