본문 바로가기
프로그래밍/Game Dev

[C#] Thread Local Storage

by YuminK 2023. 8. 28.

쓰레드는 힙 영역과 데이터 영역을 공유한다.

Thread마다 가질 수 있는 공유한 영역을 만드려면 Thread Local Storage(TLS) 를 사용하면 된다. 

 

다음 예제는 TLS로 생성한 영역에 이름을 넣고 출력하는 예제이다.

Sleep을 걸어서 다른 쓰레드가 값을 건드리는지 확실하게 체크한다. 

 

class ThreadProgram
{
    static ThreadLocal<string> ThreadName = new ThreadLocal<string>();
    //static string ThreadName;

    static void WhoAmI()
    {
        ThreadName.Value = $"My name is {Thread.CurrentThread.ManagedThreadId}";
        Thread.Sleep(1000);
        Console.WriteLine(ThreadName.Value);
    }
    static void Main(string[] args)
    {
        ThreadPool.SetMinThreads(1, 1);
        ThreadPool.SetMaxThreads(3, 3);
        Parallel.Invoke(WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI);
    }
}

 

결과: 

My name is 7
My name is 1
My name is 6
My name is 4
My name is 7 (일을 처리한 쓰레드가 다시 WhoAmI 함수를 호출한다)

 

만약 동일한 코드에서 TLS를 사용하지 않는다면?

class ThreadProgram
{
    //static ThreadLocal<string> ThreadName = new ThreadLocal<string>();
    static string ThreadName;

    static void WhoAmI()
    {
        ThreadName = $"My name is {Thread.CurrentThread.ManagedThreadId}";
        Thread.Sleep(1000);
        Console.WriteLine(ThreadName);
    }
    static void Main(string[] args)
    {
        ThreadPool.SetMinThreads(1, 1);
        ThreadPool.SetMaxThreads(3, 3);
        Parallel.Invoke(WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI);
    }
}

 

결과:

My name is 4
My name is 4
My name is 4
My name is 6
My name is 6

 

다른 쓰레드가 ThreadName 값을 바꾸고 있음을 알 수 있다.

 

다음은 TLS를 Lazy 방식으로 사용하는 예제이다.

ThreadName을 생성하지 않은 경우 등록된 함수를 호출해서 초기화한다. 

 

class ThreadProgram
{
    static ThreadLocal<string> ThreadName = new ThreadLocal<string>(() => { return $"My name is {Thread.CurrentThread.ManagedThreadId}"; });

    static void WhoAmI()
    {
        if (ThreadName.IsValueCreated)
            Console.WriteLine(ThreadName.Value + " (repeat)");
        else
            Console.WriteLine(ThreadName.Value); // lazy 방식으로 동작한다. 
    }
    static void Main(string[] args)
    {
        ThreadPool.SetMinThreads(1, 1);
        ThreadPool.SetMaxThreads(3, 3);
        Parallel.Invoke(WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI);

        // TLS 종료
        ThreadName.Dispose();
    }
}

 

결과:

My name is 1
My name is 6
My name is 7
My name is 6 (repeat)
My name is 7 (repeat)

'프로그래밍 > Game Dev' 카테고리의 다른 글

[Phaser] Animation, TileMap  (0) 2023.09.28
[Node.js] 간단한 멀티 슈팅게임 소스 분석  (0) 2023.09.26
[C#] AutoResetEvent  (0) 2023.08.26
[C#] SpinLock  (0) 2023.08.26
[C#] Interlocked  (0) 2023.08.26

댓글