Read Write Lock을 구현하며 비트에 할당하는 부분이 잘 이해가 되지 않아 배우기 쉽지 않았다. 그래도 여러번 듣다보니 익숙해져서 결국 정리는 잘 해두었지만, 반복해서 보면서 내용을 잘 기억해야겠다.
개념설명
TLS 란 각 쓰레드간의 공유-개인 사이에 있는 듯한 저장 공간이다. 쓰레드의 구조가 heap, 데이터 영역은 서로 공유하고, Stack은 독립된 공간에서 사용한다.
하지만 이때 전역으로 설정하기엔 부담스럽지만, 쓰레드 들이 공통으로 사용될만한 영역을 제공해주는게 TLS이다.(쓰레들 간의 공유가 이루어지지는 않는 고유의 공간이다)
게임 서버 동작 시에 유저들이 한 쪽으로 모이면서 쓰레드들이 처리해야 할 일감의 쏠림현상이 발생할 수 있다.
상호배제를 위해 다 lock을 걸고하자니 병목현상이 발생 할 수 있어 이런 일감을 한 번에 각자 공간(TLS)으로 가져가 처리를 하는 방식에 사용될 수 있다.
만약 Static string
으로 전역 변수를 선언 해버리면, 다른 쓰레드에서 Write 할 경우 값이 변경되어 고유의 공간에 의미가 없다.
TLS를 만들기 위해서는 ThreadLocal
기능을 활용하면 된다.
선언을 해준 뒤에 _threadLocal.Value 에 각 쓰레드의 ID 값을 넣어보며 고유의 공간을 갖게 되는지 테스트를 해본다.
Parallel.Invoke() 간단 실행법
Parallel.Invoke()를 활용하면 ThreadPool에서 가져와 편하게 쓰레드를 호출할 수 있게해준다.static void Main(string[] args) { Parallel.Invoke(WhoAmI, WhoAmI, WhoAmI, WhoAmI, WhoAmI); }
ThreadLocal.Value 값에 넣어주니 각 쓰레마다 다른 값을 출력하는 걸 확인 할 수 있다.
위와 같은 구조로 사용 시 처음에 _threadLocal.Value에 이미 id가 들어갔어도, WhoAmI() 함수가 출력 될 때 마다 새로운 값을 덮어 씌우며 불필요한 행동을 한다.
이를 해결하기 위해 이미 있는 id라면 생성하지 않고 넘어가도록 구현해보자.
bool repeat = _threadLocal.IsValueCreated;
IsValueCreated
를 활용하면 이미 제작되어 있을 경우 true 값을 return한다 이를 이용해 중복일 경우 구분을 해준다.
static ThreadLocal<String> _threadLocal
= new ThreadLocal<String>(
() => { return
$"My Name is:Thread.CurrentThread.ManagedThreadId}"; } );
이런식으로 람다를 이용해 return 값을 주게 만들면, 계속 생성하는 것이 아닌 Value 값을 체크해서 없으면 return을 통해 만들고, 있다면 그냥 넘어가도록 하는 구조이다.
사용을 모두 했다면 Dispose() 함수로 간단하게 보내줄 수 있다.
오늘 배운 TLS라는 공간을 잘 활용하면 편하게 이런 저런 작업을 지시하고, 빠른 일감 처리가 가능해질 것 같다. 이제 전반적인 멀티 쓰레드에 대한 지식은 잡혀가고 있고, 다음 네트워킹도 기대가 된다잉