본문 바로가기
프로그래밍/C++

thread_local 키워드에 대해서

by bantomak 2026. 1. 31.
반응형

thread_local 키워드란?

thread_local은 데이터 타입(Data Type)은 아니고, 저장소 지정자(Storage Class Specifier)이다.

int, double, class와 같은 자료형이 아니라, 해당 변수를 어디에, 얼마나 오랫동안 저장할 것인지를 컴파일러에게 지시하는 키워드(keyword)이다.

 

thread_local로 해당 변수의 생명주기를 설정하는 것이 가능하다. 즉, thread_local 키워드를 사용해서 변수를 선언하면 해당 변수의 생명주기는 해당 스레드의 생명주기와 동일하게 설정된다.

thread_local의 핵심 개념

thread_local 키워드가 붙은 변수는 스레드 저장 수명(Thread Storage Duration)을 가진다.

  • 독립된 복사본 : 각 스레드마다 해당 변수의 고유한 복사본을 별도로 가진다.
  • 스레드 간 상호 간섭 없음 : A 스레드가 해당 변수를 변경해도 B 스레드에 있는 같은 이름의 변수는 전혀 영향을 받지 않는다.
  • 생명주기 : 스레드가 시작할 때 생성되어서 스레드가 종료되면 소멸한다.

코드 예제

전역 변수로 생성한 local_counter 각 스레드에서 해당 변수를 참조해서 변경하지만 thread_local로 선언되어 있기 때문에 스레드별로 고유하고 독립적인 local_counter 변수를 가진다.

#include <iostream>
#include <thread>
#include <mutex>

using namespace std;

thread_local int local_counter = 0;

std::mutex mtx;

void increase_counter(int thread_id)
{
	local_counter++;
	local_counter++;

	std::lock_guard<std::mutex> lock(mtx);
	std::cout << "Thread " << thread_id << "의 local_counter 값: " << local_counter << std::endl;
}

void main()
{
	std::cout << "hello, world" << std::endl;

	std::thread thread1(increase_counter, 1);
	std::thread thread2(increase_counter, 2);
	std::thread thread3(increase_counter, 3);

	thread1.join();
	thread2.join();
	thread3.join();
}

만약에 thread_local 키워드를 제거하면 각 스레드 별로 독립적으로 존재하는 변수가 아닌 전역 변수이기 때문에 다른 결과를 얻게 된다. 아마도 각 스레드 별로 2씩 값을 올리기 때문에 6이라는 결과가 나올 것이다.

정리하자면

  • 지역 변수는 애초에 스레드 별로 독립적으로 관리된다. 각 스레드마다 별도의 스택 공간에서 관리된다.
  • thread_local 키워드를 사용하는 이유는 지역 변수는 해당 함수가 끝나면 같이 소멸하기 때문
  • 그렇다고 전역 변수를 쓰자니 전역 변수는 모든 스레드에서 접근이 가능하고 공유된다.
  • 즉, thread_local 키워드를 사용하면 각 스레드 별로 독립적으로 사용이 가능하면서 생명주기는 전역변수와 동일해진다.

일반 지역 변수 생명 주기

지역 변수는 해당 스코프를 벗어나면 자동으로 해제된다.

void func() 
{
    int count = 0; // 매번 0으로 초기화됨
    count++;
    // 함수가 끝나면 count는 메모리에서 사라짐
}

정적 변수(static) 생명 주기

스레드 간에 공유되기 때문에 모든 스레드에서 접근이 가능하다.

void func() 
{
    static int count = 0; // 프로그램 시작 시 딱 한 번 생성, 프로그램 종료 시 소멸
    count++;
    // 함수가 끝나도 값은 살아있음 (예: 1, 2, 3...)
}

스레드 로컬 변수

static과 동일한 생명 주기를 갖지만 스레드 별로 독립적으로 관리됨

void func() 
{
    // 1. 값을 기억함 (static 처럼)
    // 2. 하지만 스레드마다 별개임 (지역 변수 처럼)
    thread_local int count = 0; 
    count++;
}

함께 읽으면 좋은 글

 

메모리 구조(Memory Structure)에 대해서

메모리 구조우리가 exe 파일을 실행하면 운영체제는 프로그램에 정의된 명령어(코드)를 바탕으로 메모리에 프로세스를 적재(Load)한다. 그리고 해당 프로세스를 위한 Code, Data, Heap, Stack 영역이 생

jettstream.tistory.com

댓글