🔍 기본 개념부터 시작하자

📦 전통적인 메모리 구조

영역쓰레드 간 공유 여부비고
Stack❌ 쓰레드별로 분리됨함수 호출 스코프 종료 시 자동 소멸
Heap✅ 모든 쓰레드 공유명시적 동기화 필요 (락, atomic 등)
Data (.data, .bss)✅ 모든 쓰레드 공유전역, static 변수
TLS (Thread Local Storage)❌ 쓰레드별로 분리됨전역처럼 생겼지만 쓰레드 독립

❓ 왜 TLS가 필요한가?

  • 멀티 쓰레드 환경에서는 공유 변수에 락을 걸어야 Race Condition을 막을 수 있음
  • 하지만 쓰레드마다 사용하는 데이터가 분리될 수 있다면?
    → 처음에만 데이터를 가져와서 TLS에 저장 후, 락 없이 독립적으로 사용 가능!
// TLS를 사용하지 않았다면
// 전역 변수 LThreadId가 모든 쓰레드에서 공유되어 값이 꼬일 수 있음

// TLS 사용 시 → 쓰레드마다 LThreadId 복사본을 가짐 (경합 없음!)
thread_local int32_t LThreadId = 0;

💡 스택과 TLS의 차이

구분StackTLS
사용 목적함수 내부 임시 변수쓰레드 고유의 전역 변수
유효 범위함수 실행 중쓰레드 생존 중
안전성함수 종료 시 해제됨 (불안정)안전하게 유지됨
공유 여부공유되지 않음공유되지 않음

🐯 "호랑이가 먹이를 자기 굴에 가져가 혼자 먹는 것처럼, TLS는 쓰레드 전용 저장소야!"


🧪 실습 예제 – TLS로 쓰레드별 데이터 관리

#include <iostream>
#include <thread>
#include <vector>

thread_local int32_t LThreadId = 0;

void ThreadMain(int32_t id)
{
    LThreadId = id;

    while (true)
    {
        std::cout << "Hi! I am Thread " << LThreadId << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

int main()
{
    std::vector<std::thread> threads;

    for (int32_t i = 0; i < 5; ++i)
    {
        int32_t id = i + 1;
        threads.emplace_back(ThreadMain, id);
    }

    for (auto& t : threads)
        t.join();
}

각 쓰레드는 LThreadId를 독립적으로 가지며, 출력이 섞이지 않고 정확하게 나오는 것을 확인할 수 있다.


🧵 질문 & 심화 답변

다른 쓰레드가 특정 쓰레드의 TLS 값을 수정해야 할 상황이 오면?

Rookiss 답변 요약:

  • TLS는 원래 혼자 쓰려고 만든 공간이다.
  • 만약 원본이 힙에 있고, 공유가 필요한 값이라면?
    → 그때는 기존대로 락(mutex) 혹은 atomic 연산을 사용해야 한다.

즉, TLS는 "내가 나 혼자 쓸 값"에만 적합하다.


💬 C++11 이전 방식은?

✅ 윈도우 전용 방식 (비표준)

__declspec(thread) int32_t value;
  • 플랫폼 종속적이고, 표준 C++에서 권장되지 않음

✅ C++11 이후부터는 표준 지원!

thread_local int32_t value = 0;
  • 가독성 좋고, 모든 플랫폼에서 동작
  • 글로벌 변수처럼 선언해도 쓰레드마다 고유하게 동작

profile
李家네_공부방

0개의 댓글