ved_Rony
article thumbnail

이전에 싱글턴에 대해서 알아봤는 데, 간단히 말해 하나의 intance 만 만들어 놓고 여기저기서 가져오기 위한 패턴이다.

하지만, 싱글턴을 사용하고자 하는 클래스마다 싱글턴을 만들기엔 여러 문제가 있었고, 코드도 복잡하다. 또한, 싱글턴 패턴의 남용을 장려하지 않기 때문에, 잘 생각하고 만들어야한다.

유니티에서 싱글턴 클래스들을 한 곳으로 모아놓고 관리하는 게 편한데, 이를 위해 제네릭을 통한 싱글턴을 만들고자 한다.

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T _Instance;
 
    public static T Instance
    {
        get
        {
             if (_Instance == null)
             {
                 _Instance = (T)FindObjectOfType(typeof(T));
 
                 if (_Instance == null)
                 {
                     var obj = new GameObject();
                     _Instance = obj.AddComponent<T>();
                     singletonObject.name = typeof(T).ToString() + " (Singleton)";
 
                     DontDestroyOnLoad(singletonObject); 
                   }
             }
             return _Instance;
        }
    }
}

단순 인스턴스 생성 여부 판단후, 인스턴스가 생성이 안되었다면, 새로 인스턴스를 생성해준다. 위의 Addcomponent는 유니티에서 쓰인 싱글턴 제네릭이기 때문에 쓰였다.

하지만, 위의 경우 문제가 있다. 유니티는 싱글 쓰레드 환경이기 때문에, 큰문제가 없지만, 다른 멀티 쓰레드의 환경일 경우, 서로다른 쓰레드에서 intance init에 대한 요청이 들어오면 if(instance ==null)이 참이 될수도 있기 때문이다.

    private static object _Lock = new object();
 
    public static T Instance
    {
        get
        {
            lock (_Lock)
            {

위의 부분에 lock을 추가 해주는 것이다. 이와 같은 경우 먼저 요청된 thread가 먼저 실행이 되고 다른 쓰레드는 먼저 실행된 쓰레드가 released되면 실행이 되기 때문에 이때 thread는 instance ==null에 대해 false를 반환할수 있다. 대신, 이같은 lock을 쓰게 되는 경우 성능을 많이 잡아 먹게 되는데, https://csharpindepth.com/articles/Singleton 에  Unfortunately, performance suffers as a lock is acquired every time the instance is requested.라고 자세히 나와있다. 뒤에 lazy문을 사용해서 쉽게 만들수가 있으나, .NET 4이상의 환경에서만 제공이 가능하니 이전 버전에서는 고려 사항이 아니다.

따라서, 경우에 따라 맞는 방식을 취하면 되겠다.

유니티에서 singleton manager를 사용하는 경우, 앱시작 초반 manager 클래스 몇가지를 미리 생성 해주는 것으로 lock으로 thread-safe를 구현 해놓으면, 성능 차원에서도 큰차이를 만들지 않고 더 안전하게 싱글턴 intance를 생성 할수 있을거라 생각한다.

추가로 

    private static bool _ShuttingDown = false;
    private static object _Lock = new object();
    private static T _Instance;
 
    public static T Instance
    {
        get
        {
            if (_ShuttingDown)
            {
                return null;
            }

   private void OnApplicationQuit()
    {
        _ShuttingDown = true;
    }
 
    private void OnDestroy()
    {
        _ShuttingDown = true;
    }

위 코드로 앱 종료시 null 체크를 한번 해주는 것이 안전하다.

profile

ved_Rony

@Rony_chan

검색 태그