포스트

C#에서 Thread Local Storage 사용하기

쓰레드를 생성하면 각 쓰레드마다 고유의 스택을 할당받는다는 것은 다들 아실텐데요, 이번에는 C#에서 쓰레드 고유의 로컬 스토리지를 사용하는 방법을 알아보겠습니다. TLS(Thread Local Storage)는 쓰레드마다 고유하게 접근할 수 있는 전역변수입니다.

TLS가 필요한 이유는 식당에서 서빙하는 점원들을 예로 들어서 이해하면 쉽습니다. 손님 테이블에 반찬 여러 개를 옮기기 위해 여러 점원들이 반찬 하나하나를 오가며 옮기는 것보다는 한 점원이 큰 쟁반에 여러 반찬들을 한번에 모아서 서빙하는게 자연스럽죠? 이렇게 옮겨야 하는 것들을 큰 덩어리로 옮기고 테이블에서 하나씩 내려놓을 때 그 덩어리를 TLS라고 이해하시면 쉬울 것 같습니다.

C#에서 TLS를 사용하는 방법은 매우 간단합니다. 바로 ThreadLocal<>로 래핑해서 사용하시면 됩니다. 한 번 사용해봅시다.

원래는 다음과 같았던 코드에서는 Thread가 전역적으로 변수를 공유합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;
using System.Data;
using System.Threading;
using System.Threading.Tasks;

namespace ServerCore
{

    internal class Program
    {
        static string ThreadName;

        static void WhoAmI()
        {
            ThreadName &#x3D; $"My Name is {Thread.CurrentThread.ManagedThreadId}";

            Thread.Sleep(1000);

            Console.WriteLine(ThreadName);
        }

        static void Main(string[] args)
        {
            Parallel.Invoke(WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI);   
        }
    }
}

전역적으로 ThreadName 변수를 공유했으므로 모두 똑같은 이름을 가지고 있습니다. 그럼, 이제는 ThreadID값을 다음과 같이 ThreadLocal<> TLS변수로 매핑해준다면 각 Thread에서 관리하는 스토리지 안에서 변수가 생성되게 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System;
using System.Data;
using System.Threading;
using System.Threading.Tasks;

namespace ServerCore
{
    // 전역(static공간)에 있는 [ JobQueue ] 에 락을 걸어서 접근한 다음 한번에 최대한 많은 일감을 빼오면, 락을 하는 횟수를 줄일 수 있다.
    class Program
    {
        // TLS공간 사용하기: ThreadLocal
        static ThreadLocal ThreadName &#x3D; new ThreadLocal(() &#x3D;> { return $"My Name is {Thread.CurrentThread.ManagedThreadId}"; });

        static void WhoAmI()
        {
            bool repeat &#x3D; ThreadName.IsValueCreated;
            if (repeat)
                Console.WriteLine(ThreadName.Value + "(repeat)");
            else
                Console.WriteLine(ThreadName.Value);
        }

        static void Main(string[] args)
        {
            ThreadPool.SetMinThreads(1, 1);
            ThreadPool.SetMaxThreads(3, 3);
            Parallel.Invoke(WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI);

            ThreadName.Dispose();
        }
    }
}

그 결과, 위와 같이 각 쓰레드들이 서로 다른 이름을 가지고 있는 것을 확인했습니다. 쓰레드 각자의 이름을 TLS라고 하는 각각의 로컬 스토리지에 저장했기 때문입니다.

지금까지 C#에서 TLS를 간단히 사용해보았습니다. 감사합니다:)

인프런의 '[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버' 강의를 참고하여 정리 목적으로 작성하고 있습니다. 실제 강의 내용의 모든 부분을 다루고 있지는 않습니다. 감사합니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.