반응형

멀티 스레드 환경에서 각 스레드별로 하나의 공통 데이터에 접근하여 처리 될때 스레드 마다 원자성을 보장하면서
데이터를 다뤄야 하는 상황이 발생할 수 있습니다.

이때 제공 되는것이 Thread Local Storage(TLS) 변수라는 것이 있습니다.

쉽게 말해 tls변수는 스레드별 고유한 데이터를 저장(?)할 수 있는 공간이라고 이해 하면 됩니다. 또한 이 tls변수는(이하 거론되는 ThreadLocal<T> AsyncLocal<T> 동일) 자체적으로 데이터 원자성이 보장되기에 lock없이 접근하여 사용이 가능합니다.

닷넷 C#에서는 이것을 System.ThreadStaticAttribute 어트리뷰트 클래스로 제공 하고 있으며
System.Threading.ThreadLocal<T> 그리고 System.Threading.AsyncLocal<T> 클래스로 제공하고 있고, C++에서는 __declspec(thread)로 사용 가능합니다.

System.Threading.ThreadLocal<T> 같은 경우 System.ThreadStaticAttribute 보다 변수 초기 방법을 제공하고 있어 [ThreadStatic] 어트리뷰트 보다 좀 더 최신 기능을 제공합니다.

이번 포스트는 System.Threading.ThreadLocal<T>  System.Threading.AsyncLocal<T> 가 서로 어떤 부분에 차이점이 있는지에 대한 내용 입니다.

자 그럼 어떻게 다른지 살펴보겠습니다.

ThreadLocal<T> AsyncLocal<T> 차이점

위 tls역할을 하는 두 클래스의 큰 차이점은 스레드풀을 사용하는 스레드 환경에서 차이점이 있습니다.

우선 System.Threading.ThreadLocal<T> 은 해당 스레드가 스레드풀에 반환되어도 해당 데이터는 항상 유지 되어 집니다.

private static ThreadLocal<int> _tl = new ThreadLocal<int>();

private static async Task WorkAsync(int i)
{
  if(_tl.Value == 0)
  {
    _tl.Value = i;
    Console.WriteLine($"[새로운 값] Thread Id : {Environment.CurrentManagedThreadId} - tl Value : {_tl.Value}");
  }
  else
  {
    Console.WriteLine($"[기존 값] Thread Id : {Environment.CurrentManagedThreadId} - tl Value : {_tl.Value}");
  }
  Console.WriteLine("-----------------------------------------");
}

위 처럼 System.Threading.ThreadLocal<T> 을 사용하는 메서드를 스레드로 호출해 봅니다. 그리고 차이점을 확실히 보기 위해 스레드풀의 스레드 개수 제한을 4개로 설정해 보았습니다.

// ThreadPool의 개수를 4개로 임의 제한
ThreadPool.SetMinThreads(4, 4);
ThreadPool.SetMaxThreads(4, 4);

for (int i = 1; i < 11; i++)
{
  await Task.Run(() => WorkAsync(i));
}

스레드를 사용하여 WorkAsync() 메서드를 10번 호출하였고 파라메터로 tls값을 동시에 넘겨 주었습니다.

결과는 어떻게 나올까요?

위 처럼 처음 스레드가 사용되어서 tls값이 설정 되고 해당 스레드가 반환된 이후 다시 같은 스레드가 사용 되었을때
tls값이 처음 설정 된 값으로 유지 되고 있는 걸 확인 할 수 있습니다.

반면,

AsyncLocal<T> 는 어떻게 처리 되는지 위 코드에서 System.Threading.ThreadLocal<T> 부분만 바꿔서 실행 시켜 보겠습니다.

결과를 보니 위 결과와는 다르게 사용된 스레드가 스레드풀에 반환될때는 값이 초기화가 되는 걸 볼 수 있습니다.

 

ref :https://blog.arong.info/c%23/2022/01/14/C-ThreadLocal-T-%EC%99%80-AsyncLocal-T-%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90.html

반응형

'프로그래밍(Programming) > C#' 카테고리의 다른 글

async/await & 커피와 베이컨  (0) 2023.04.07
C# - ArraySegment  (0) 2023.01.04
Common Memory Leaks In C#  (0) 2022.12.04
C# 에서 Dispose  (0) 2022.12.04
ReaderWriterLockSlim  (0) 2022.11.27

+ Recent posts