C#/네트워크

[c#][서버] Thread Local Storage

goliot 2024. 6. 3. 18:25
반응형

고오급 식당

  • 주문, 조리, 결제 등이 딱딱 아름답게 나뉘어 있지 않음
  • 반드시 왔다갔다 해야 함
    • 각 과정에 락을 다 걸어야 혼선이 생기지 않겠지?
    • 여러 직원이 한 테이블의 일에 몰리지 않게
  • 즉 게임으로 치면
    • DB, 게임 로직, 클라이언트 세션, 로그 등
    • 멀티쓰레드로 얘네의 일감 분배를 아름답게 해줘야겠지
  • 무조건 멀티쓰레드라고 락 걸고 쓰레드를 늘리는게 능사가 아니다.
    • 좁은 공간에 여러 직원이 들어가 봤자 일하기 더 불편해질 뿐이다

Thread Local Storage

  • Stack 영역은 각 쓰레드에 별도로 존재
    • 임시 메모리이므로 여기다가 무얼 저장한 다는 것은 불안정
  • Heap, 데이터 영역은 모든 쓰레드가 공유
    • 여기에다가 각 쓰레드의 개인 공간을 만들어 준다면?
    • 이게 TLS의 개념
static ThreadLocal<string> ThreadName = new ThreadLocal<string>();
//전역에 저장되긴 하지만 각 쓰레드만의 공간에 저장됨
//다른 쓰레드에 영향을 주지 않음

static void WhoAmI()
{
    ThreadName.Value = $"My name is {Thread.CurrentThread.ManagedThreadId}";

    Thread.Sleep(1000);

    Console.WriteLine(ThreadName.Value);
}

static void Main(string[] args)
{
    Parallel.Invoke(WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI);
    //인자로 넣은 것 각각을 Task로 만들어서 실행해줌
}
  • 그냥 전역 string이 아닌, ThreadLocal<string>으로 래핑을 했기 때문에, 각 쓰레드마다 따로 관리가 들어감
  • Paralle.Invoke로 6번 실행해 본다면?
    •  

변수를 하나 설정했지만, 각각 다른 값이 나오는 모습

  • 래핑하지 않고 그냥 쓴다면, 모두 같은 값이 나온다.
  • 만약, 쓰레드 개수의 최대 최소를 설정한다면?
    • Parallel도 결국 풀링을 하는 애이기 때문에 중복된 쓰레드가 나올 수 밖에 없음
    • 그러면 중복된 앤지 어떻게 구분하는가
static ThreadLocal<string> ThreadName = new ThreadLocal<string>(() =>
{
    return $"My name is {Thread.CurrentThread.ManagedThreadId}";
}); //람다 함수로 선언과 동시에 값을 리턴

static void WhoAmI()
{
    bool repeat = ThreadName.IsValueCreated; //value가 설정이 되었는지 아닌지 여부를 반환
    
    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);
}
  • 이렇게 처리할 수 있다.
    •  

3개 까지는 새거, 나머지 3개는 중복된 쓰레드가 나오는 모습

  • 만들어진 Value를 지우려면
    • ThreadName.Dispose();
    • 람다로 리턴했던 값을 지운다.

Thread Local Storage의 용도

  • 우선 TLS에 저장된 값은, 자신만의 데이터이므로 락을 걸 필요가 없음
    • 그러므로, 공용 공간에 접근하는 횟수를 줄이는 것 만으로도 의미가 있음
    • 락을 잠갔다 풀었다 하는 오버헤드가 나오지 않음
    • 즉, 락을 한 번 얻었을 때 TLS에다가 최대한 많이 뽑아 온다면, 다음엔 락에 접근할 필요가 없어지는 것
  • Thread의 고유한 이름이나 ID 등을 사용해야 할 때 TLS를 사용하자
  • 여기까지가 쓰레드의 기본기
반응형

'C# > 네트워크' 카테고리의 다른 글

[c#][서버] 소켓 프로그래밍  (0) 2024.06.05
[c#][서버] 네트워크 기초 이론  (0) 2024.06.04
[c#][서버] ReaderWriterLock  (0) 2024.06.03
[c#][서버] Lock 구현 이론  (0) 2024.06.02
[c#][서버] 데드락  (0) 2024.06.02