쓰레드들은 Heap 영역과 데이터 영역 (static 변수 ) 는 같이 공유한다.
반면 Stack은 쓰레드들 끼리 따로 따로 사용한다.
그래서 Heap 영역이나 데이터 영역에 동시 접근하려면은 Lock 을 걸든 해서 동기화를 해줘 한번에 한번씩 사용하게 해줬다.
근데 사실 이거 뿐만 아니라 TLS 라는 것이 하나 더 있다.
Thread Local Storage : 쓰레드들 마다 각기 가지고 있는 독립적인 저장 공간.
Heap이나 데이터 영역에 있는 공유해서 사용하는 변수들이 있다고 했을때, 자기가 사용할 데이터를 충분히 큼지막하게 TLS 로 끌고 온 다음에 TLS 에서 사용하게 되면은, 처음에 큼지막하게 꺼내올때만 Lock 을 걸어 옮겨 놓는다면 그 다음에서는 TLS가 본인 혼자서만 접근할 수 있는 영역이기 때문에 별도의 경합이 일어나지 않는다.
그럼 스택이랑 TLS랑 뭐가 다르나?
- 스택은 : 함수를 위한 메모리 공간. 함수가 끝나서 스택프레임이 정리가 되면서 일부분은 유효하지 않게 되는 굉장히 불안정한 공간.
- 반대로 TLS 는 일반적인 데이터 영역처럼 사용할 수 있고, 전역 변수지만 나만 사용하는 전역 변수 느낌이다.
ex ) 호랑이가 먹이를 먹을때 한 덩어리를 뜯어와서 자기만의 공간에 가서 얌얌 그 고기를 씹는거랑 비슷하다.
내 질문 :
Q ) TLS가 쓰레드들 마다 각기 가지고 있는 독립적인 저장공간이고, 처음에만 Lock을 걸고 이후부터는 별도의 경합이 없다면, 다른 쓰레드들이 특정 쓰레드의 TLS 에 있는 전역변수를 수정해야되는 상황이 온다면 어떻게 해야하나?
Rookiss 답변 :
A ) 기본적으로 TLS을 사용하는건 경합없이 혼자 독식하려는 의도로 사용하는 것이지만,
만약 그 데이터 원본이 힙 영역에 존재하고 심지어 경합이 붙는 데이터라면
당연히 기존과 마찬가지로 락을 이용하거나 atomic 한 방법을 찾거나 해야 합니다.
[ 실습 ]
예전 C++11이전에는 TLS 를 사용하는 방법이 OS 마다 달랐다.
c++ 11 이후에는 표준적인 방법으로 TLS를 사용할 수 있게 되었다.
최신 방법은
변수 앞에다가 thread_local 을 붙히게 된다.
그러면 일반적인 전역 변수가 아니라 쓰레드 자신만 접근 할 수 있는 TLS 영역에 잡히게 된다 .
만약 LThreadId 가 thread_local 변수가 아닌 그냥 전역 변수 였다면
전역으로 사용하는 메모리이다 보니깐 다른 쓰레드가 LTrheadId 사용하면 덮어 써져서 기존의 값이 날라가겠지만,
thread_local을 하면은 쓰레드마다 자신만의 공간을 따로 따로 가지고 있을거기 때문에 ID 자체는 아래 결과처럼 정상적으로 발급된것을 볼 수 있다.
'C++과 언리얼로 만드는 게임 개발 > Part4. Server' 카테고리의 다른 글
★(중요)Local-Based Stack/Queue | V (0) | 2022.06.25 |
---|---|
★진짜 진짜 중요!!!★메모리 모델 | atomic 클래스/ 가시성 / 코드 재배치 (0) | 2022.06.08 |
캐시 & CPU 파이프라인 ★★ 문제 제시 | V (0) | 2022.06.06 |
std::future | V (0) | 2022.05.21 |
Event ( 커널 오브젝트, CreateEvent, WaitForSingleObject ) | V (0) | 2022.05.02 |