[컴][C#] C# 에서 singleton 을 구현하는 방법


출처 : Implementing Singleton in C#

using System;

public class Singleton
{
   private static Singleton instance;

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null)
         {
            instance = new Singleton();
         }
         return instance;
      }
   }
}

위와같은 Singleton 의 구현은 2가지 이득이 있다.
  1. instance 가 Instance property 내부에서 만들어지기 때문에 그 안에서 원하는 작업을 추가할 수 있다.
  2. object 가 instance 를 사용요청을 하기 전까지는 안 만들어진다.(lazy instantiation)


그런데 이 녀석은 multithreaded programming 에서 안전하지 않다. instance 가 null 인지 비교하는 경우에 race condition 이 발생해서 여러 개의 singleton 을 만들어 버릴 수 있다.



Static Initialization


c++ 스펙에서는 static variable 의 초기화 순서에 대한 모호함이 있어서 원래 design pattern 에서는 static intialization 을 잘 안 쓴다.

근데 .NET Framework 에서는 변수 초기화의 처리를 통해 이 모호함(ambiguity) 를 해결했다.

 
public sealed class Singleton
{
   private static readonly Singleton instance = new Singleton();
   
   private Singleton(){}

   public static Singleton Instance
   {
      get 
      {
         return instance; 
      }
   }
}
 

이 코드에서는 class 에 있는 member 중 하나가 referenced 되면, instance 가 만들어지게 된다.

CLR 이 variable initialization 을 관리한다.

상속이 instance 를 추가할 수도 있어서, 상속을 막기 위해 sealed keyword 를 사용하였다.

varable 은 readonly 로 했다. readonly 은 초기화를 한 번만 할 수 있기 때문에 오직 static initialization 하는 동안에만 assign 된다.

하지만 여전히 singleton 의 기본적인 문제인 global access 와 instantiation contorl 은 가지고 있다.

이 경우에 문제는 CLR 이 intialization 을 하고 있어서 원하는 대로 초기화를 할 수 없다.

.NET 에서 가장 선호되는 방식이다.



Multithreaded

Multithreaded 에서는 아래 처럼 다른 방법을 써야한다.

using System;

public sealed class Singleton
{
   private static volatile Singleton instance;
   private static object syncRoot = new Object();

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null) 
         {
            lock (syncRoot) 
            {
               if (instance == null) 
                  instance = new Singleton();
            }
         }

         return instance;
      }
   }
}

댓글 없음:

댓글 쓰기