C++에서 std::thread를 이용한 스레드 생성, 관리, 동기화 기초 실습 정리
하나의 프로세스에서 여러 개의 스레드를 생성하고, 병렬로 작업을 처리하며, join, detach, joinable, hardware_concurrency 등 핵심 API 사용법과 그 의미를 실습 코드와 함께 학습한 내용을 완전하게 정리한 글이다.
std::thread를 통해 OS에 상관없이 동일한 방식으로 스레드를 생성하고 실행할 수 있다.std::thread 생성자에 실행할 함수와 인자를 넘겨주면 바로 새로운 스레드가 시작된다.join()으로 명시적으로 종료될 때까지 기다리거나, 또는 detach()로 분리해서 백그라운드에서 실행시킬 수 있다.join() 또는 detach()를 하지 않고 std::thread 객체가 소멸되면 std::terminate()가 호출된다.std::thread는 내부적으로 가변 템플릿 생성자를 사용하므로, 인자 개수와 타입이 다양해도 함수와 함께 넘기기만 하면 자동으로 처리된다.std::thread(HelloThread2, 10);mutex, atomic 등)를 사용하지 않으면 데이터 손상 위험이 있다.| 용어 | 설명 |
|---|---|
std::thread | C++ 표준 스레드 클래스. 스레드 생성 및 제어를 담당 |
join() | 현재 스레드가 대상 스레드가 종료될 때까지 대기 |
detach() | 스레드를 백그라운드에서 실행하도록 분리 (제어권 상실) |
joinable() | 해당 스레드 객체가 조인 가능한 상태인지 확인 |
get_id() | 해당 스레드 고유 ID 반환 |
hardware_concurrency() | 사용 가능한 논리 CPU 코어 수 반환 |
| 가변 템플릿 생성자 | 함수 인자 개수와 타입에 맞게 유연하게 처리하는 생성자 구조 |
std::thread t;
auto id1 = t.get_id(); // 아직 실행할 함수가 없으므로 id는 0
t = std::thread(HelloThread); // HelloThread 함수 실행하는 쓰레드 생성
int32 count = t.hardware_concurrency(); // 시스템의 논리 코어 수 반환
auto id2 = t.get_id(); // 실제 실행되는 쓰레드 ID
if (t.joinable())
t.join(); // 스레드 종료까지 대기
cout << "Hello Main" << endl;
📌 std::thread 객체는 함수 실행과 동시에 스레드를 시작한다. join()을 호출하지 않으면 main()이 먼저 끝날 수 있어 위험하다.
std::vector<std::thread> threadVec;
for (int32 i = 0; i < 10; ++i)
{
threadVec.push_back(std::thread(HelloThread2, i)); // i값 전달하여 10개 스레드 생성
}
for (int32 i = 0; i < 10; ++i)
{
if (threadVec[i].joinable())
threadVec[i].join(); // 각각의 스레드 종료까지 기다림
}
cout << "Main Finished!" << endl;
📌 스레드 객체를 컨테이너에 저장하여 여러 개를 생성하고 관리할 수 있다. 실행 순서는 OS 스케줄러에 따라 랜덤하므로 출력 순서도 비결정적이다.
int32 sum = 0;
void Add()
{
for (int32 i = 0; i < 100'0000; i++)
{
int32 eax = sum;
eax = eax + 1;
sum = eax;
}
}
void Sub()
{
for (int32 i = 0; i < 100'0000; i++)
{
int32 eax = sum;
eax = eax - 1;
sum = eax;
}
}
int main()
{
Add(); Sub();
cout << sum << endl; // 항상 0
std::thread t1(Add);
std::thread t2(Sub);
t1.join(); t2.join();
cout << sum << endl; // 실행할 때마다 결과가 달라짐!
}
📌 Add()와 Sub()을 각각 순차적으로 호출하면 결과는 항상 0이지만, 스레드로 병렬 실행하면 결과가 매번 달라진다. 이건 전형적인 경쟁 조건(Race Condition) 문제다.
std::thread는 C++에서 멀티스레딩을 구현할 수 있는 핵심 클래스이며, 함수와 인자를 넘기면 실행 즉시 스레드가 시작된다.join() 또는 detach()를 호출해 종료를 명시적으로 처리해야 한다. 안 하면 std::terminate()가 호출된다.vector<thread> 등 컨테이너로 관리하면 편리하다.hardware_concurrency()는 시스템의 코어 수를 반환하므로, 쓰레드 풀 구성이나 스레드 수 조절 시 유용하다.mutex, atomic 등의 동기화 장치를 사용해야 한다.std::thread의 생성자는 가변 템플릿으로 구성되어 있어 인자 전달을 자동으로 처리한다.