(C#) Thread Local Storage (TLS)
포스트
취소

(C#) Thread Local Storage (TLS)

TLS란?

TLS는 Thread Local Storage의 약자로 각 스레드마다 저장공간을 가지는 방법이다.

정적인 전역 변수가 존재할 때 여러 스레드가 그 변수를 사용한다면 독점권으로 인해

Lock을 걸었다 풀었다하기 때문에 싱글스레드보다 오히려 비효율적으로 사용되게 된다.

TLS는 그러한 변수를 각 스레드에게 자신만의 공간에서 다른 스레드의 간섭이 없도록 사용할 수 있게 해준다.

💻 코드

TLS 사용방법은 ThreadLocal 클래스를 사용하여 정적인 변수를 스레드가 사용했을 때 자신만의 공간에서 사용이 가능하다.

아래 코드는 WhoAmI를 여러 스레드가 동시에 접근하여 사용했을 때

각 스레드에서 threadName의 ID가 몇으로 나오는지 확인하는 코드이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static ThreadLocal<string> threadName = new ThreadLocal<string>();

static void WhoAmI()
{
    // ThreadLocal에 값을 넣을때는 .Value하여 쓰거나 읽을 수 있다.
    threadName.Value = $"My Name Is {Thread.CurrentThread.ManagedThreadId}";

    Thread.Sleep(1000);

    Console.WriteLine(threadName.Value);
}

static void Main(string[] args)
{
    // Task를 여러개 만들어서 한번에 호출하기 번거로우니 Parallel 사용.
    Parallel.Invoke(WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI);
}


컴파일을 해보면 threadName을 사용하는 스레드 ID가 전부 다른것을 확인할 수 있다.

이는 스레드가 자신만의 공간에서 외부 간섭없이 threadName을 사용한 것이다.

🛠 ThreadLocal을 사용안했을 때

만약 ThreadLocal을 사용하지 않고 정적인 string 변수로 사용할 경우 결과는 다음과 같다.

1
2
// static ThreadLocal<string> threadName = new ThreadLocal<string>();
static string threadName;


컴파일 결과 스레드 ID가 모두 같은것을 확인할 수 있다.

🛠 스레드 개수를 정해줬을 때

만약 ThreadPool을 사용하여 스레드의 수를 제안했을 때 결과를 확인해본다.

1
2
ThreadPool.SetMinThreads(1, 1);
ThreadPool.SetMaxThreads(3, 3);


결과를 확인해보면 스레드 개수를 제안했을 뿐인데 스레드 ID가 중복되어 출력된 것을 볼 수 있다.

하지만 스레드 ID 출력값이 같아 TLS가 제대로 작동안했나 할 수 있지만 TLS는 정상적으로 작동하였다.

다음 코드처럼 수정하여 다시 확인해보도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// threadName을 스레드가 사용하면 ThreadLocal을 생성할 때 매개변수로 전달된 값이 Value에 저장된다.
static ThreadLocal<string> threadName = new ThreadLocal<string>(() => { return $"My Name Is {Thread.CurrentThread.ManagedThreadId}"; });

static void WhoAmI()
{
    // .IsValueCreadted를 통해 재사용 됐는지 확인
    bool repeat = 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, WhoAmI);

    // threadName 값 초기화
    threadName.Dispose();
}


결과를 보면 같은 스레드ID를 재사용했을 때 (repeat)가 붙어있는 것을 확인할 수 있다.

결론

코드 실습을 통해 TLS 사용법을 알 수 있었고 각 스레드의 공간에서 정적인 변수를 사용할 수 있다는 것을 확인할 수 있었다.


💡 참고

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

(C#) ReaderWriterLock 구현 연습

네트워크 기초