쓰레드들은 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 자체는 아래 결과처럼 정상적으로 발급된것을 볼 수 있다.

 

+ Recent posts