서버/서버 이론

Thread Local Storage (TLS)

잼잼재미 2025. 4. 6. 16:52

Thread Local Storage (TLS)


멀티 쓰레드 환경이라고 무조건 Lock을 거는 것은 효율적이지 않다. MMO RPG의 경우 여러 유저들이 동시에 한 곳에 각각 패킷을 보내는 경우가 많이 때문에 이때는 Lock을 거는 것은 과부하가 걸릴 수 있다. 무조건 Lock을 걸어서 멀티 쓰레드 환경을 구축하는 것도 가능은 하지만, 경우에 따라서는 (MMO RPG 같은) 무조건 Lock을 걸면 안된다는 것이다. 

 

ex) 식당에서 각각의 점원들은 서로의 구역에 어느정도 상호작용하고 있고, 한번에 여러 직원이 같은 구역에 몰릴 가능성도 있다.

 

이렇게 한 곳에 동시에 패킷을 보내는 경우, 각각 Lock을 걸어서 처리하는 것이 아니라 공통적인 부분은 함께 같이 처리하는 방법이 필요하다.

 

ex) 식당의 여러 테이블에서 동일한 메뉴를 동시에 주문하면, 각각 사이드 메뉴를 세팅하는 것이 아니라, 한꺼번에 옮겨서 세팅해준다.

 

그래서 각자 쓰레드가 따로 따로 사용할 수 있는 나만의 전역 공간이 필요하다. 이것이 바로 TLS 이다. 

 

 

class Program
{
   static ThreadLocal<string> ThreadName = new ThreadLocal<string>();
        
    static void WhoAmI()
    {
        //실제 타입(string)은 .Value에 있음
        ThreadName.Value = $"My Name Is {Thread.CurrentThread.ManagedThreadId}";

        Thread.Sleep(1000);

        //ThreadName.Value 출력
        Console.WriteLine(ThreadName.Value);
    }

    private static void Main(string[] args)
    {
        //Invoke에 넣는 액션만큼을 편리하게 태스크로 만들어 스레드풀에 있는 스레드가 호출하도록 함
        Parallel.Invoke(WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI);
    }
}

 

이와 같이 코드를 실행하면, 모두 다른 쓰레드 아이디가 호출된다.

 

 

ThreadPool을 사용할 때, 이미 앞에서 사용했던 쓰레드를 다시 재사용하는 경우, 위의 ThreadName.Value에 또 다시 Thread.CurrentThread.ManagedThreadId 값을 뒤집어 씌우는 작업을 하고 있다. 이러한 부분이 마음에 들지 않는다면 아래와 같이 코드를 작성할 수 있다.

 

class Program
{
    static ThreadLocal<string> ThreadName = new ThreadLocal<string>(() =>
    {
        //ThreadName이라는 변수가 현재 값 생성이 안되어있다면, 생성
        return $"My Name Is {Thread.CurrentThread.ManagedThreadId}";
    });

    static void WhoAmI()
    {
        if (ThreadName.IsValueCreated) //이미 값이 있음
        {
            Console.WriteLine(ThreadName.Value + " 이미 생성됨");
        }
        else //최초로 만듬
        {
            Console.WriteLine(ThreadName.Value);
        }

        Thread.Sleep(1000);
    }

    private static void Main(string[] args)
    {
        //스레드풀의 크기를 제한
        ThreadPool.SetMinThreads(1, 1);
        ThreadPool.SetMaxThreads(3, 3);

        Parallel.Invoke(WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI);

        ThreadName.Dispose(); //필요없어진경우 Dispose로 제거(모든 스레드 값 제거)
    }
}

 

 

이와 같이 호출되는 것을 확인할 수 있다.

'서버 > 서버 이론' 카테고리의 다른 글

소켓 프로그래밍 기초  (0) 2025.04.09
네트워크 기초 이론  (0) 2025.04.07
Lock 구현  (0) 2025.03.29
데드락 (DeadLock)  (0) 2025.03.28
Lock  (0) 2025.03.27