std::thread
개요
std::thread
는 C++11부터 표준 라이브러리에 추가된 기능으로, 프로그램 내에서 새로운 스레드를 생성하고 관리할 수 있게 해주는 클래스입니다. 이를 통해 병렬(Parallel) 또는 동시성(Concurrent) 프로그래밍을 구현하여 프로그램의 성능을 향상시키거나 응답성을 높일 수 있습니다.
C++ 버전별 주요 키워드 도입 시기
- C++11:
std::thread
및 관련 기능들이<thread>
헤더에 처음 도입되었습니다.
내용 설명
std::thread
객체는 생성 시 인자로 전달된 함수(또는 호출 가능한 객체)를 새로운 스레드에서 실행합니다. std::thread
의 주요 특징은 다음과 같습니다.
- 생성과 실행:
std::thread
객체를 생성하면 즉시 새로운 스레드가 실행을 시작합니다. 첫 번째 인자로는 스레드에서 실행할 함수, 람다 표현식, 함수 객체 등을 전달하고, 이후 인자들은 해당 함수에 전달될 인자들입니다. - 인자 전달: 스레드 함수에 인자를 전달할 때, 기본적으로 값에 의한 복사(copy) 또는 이동(move)이 일어납니다. 만약 참조(reference)로 인자를 전달하고 싶다면
std::ref
를 사용해야 합니다. 예제 코드의std::ref(outputs[i])
가 바로 그 예시입니다. - Join:
join()
멤버 함수는 해당 스레드가 작업을 완료할 때까지 현재 스레드(주로 메인 스레드)를 대기시킵니다.join()
을 호출하지 않고std::thread
객체의 소멸자가 호출되면 프로그램이 비정상적으로 종료(std::terminate
)되므로, 생성된 스레드는 반드시join()
또는detach()
를 호출해야 합니다. - Detach:
detach()
멤버 함수는 스레드를 생성한 스레드로부터 분리합니다.detach
된 스레드는 백그라운드에서 독립적으로 실행되며, 더 이상join
할 수 없습니다.detach
된 스레드는 실행이 끝나면 스스로 자원을 해제합니다. - 스레드 ID:
std::this_thread::get_id()
함수를 통해 현재 실행 중인 스레드의 고유 ID를 얻을 수 있습니다.
예제 코드
#include <array>
#include <cstdint>
#include <iostream>
#include <numeric>
#include <thread>
#include <chrono>
namespace
{
constexpr auto NUM_THREADS = size_t{3U};
};
void worker(const std::int32_t input, std::int32_t &output)
{
std::cout << "Called worker from Thread: " << std::this_thread::get_id()
<< '\n';
output = input * 2;
std::this_thread::sleep_for(std::chrono::seconds(20));
}
int main()
{
auto inputs = std::array<std::int32_t, NUM_THREADS>{};
std::iota(inputs.begin(), inputs.end(), 0);
auto outputs = std::array<std::int32_t, NUM_THREADS>{};
std::fill(outputs.begin(), outputs.end(), 0);
std::cout << "Main Thread ID: " << std::this_thread::get_id() << '\n';
std::array<std::thread, NUM_THREADS> threads;
for (std::uint32_t i = 0; i < NUM_THREADS; ++i)
{
threads[i] = std::thread(worker, inputs[i], std::ref(outputs[i]));
}
// ...
for (std::uint32_t i = 0; i < NUM_THREADS; ++i)
{
threads[i].join();
}
for (std::uint32_t i = 0; i < NUM_THREADS; ++i)
{
std::cout << "Outputs[" << i << "] = " << outputs[i] << '\n';
}
return 0;
}
실행 결과
Main Thread ID: 140735252825920
Called worker from Thread: 140735252825921
Called worker from Thread: 140735252825922
Called worker from Thread: 140735252825923
// -- 20초 대기 --
Outputs[0] = 0
Outputs[1] = 2
Outputs[2] = 4
참고: 스레드 ID는 실행할 때마다 달라질 수 있으며,
Called worker from Thread
메시지의 출력 순서는 스케줄링에 따라 보장되지 않습니다.
활용팁
- RAII (Resource Acquisition Is Initialization) 패턴 활용:
std::thread
객체가 소멸될 때join()
이나detach()
가 호출되도록 보장하는 래퍼(wrapper) 클래스를 만들면 예외 발생 시에도 안전하게 스레드 자원을 관리할 수 있습니다. std::thread::hardware_concurrency()
: 이 함수는 시스템이 지원하는 동시 스레드의 수를 반환합니다. 스레드 풀(thread pool)의 크기를 결정하는 등 최적화에 유용하게 사용할 수 있습니다. (단, 이 값은 힌트일 뿐이며 0을 반환할 수도 있습니다.)- 데이터 경쟁(Data Race) 주의: 여러 스레드가 공유 데이터에 동시에 접근할 때는 데이터 경쟁이 발생할 수 있습니다. 예제에서는 각 스레드가
outputs
배열의 서로 다른 원소에만 접근하므로 안전하지만, 공유 자원에 쓰기 작업을 할 때는std::mutex
,std::atomic
등을 사용하여 동기화를 해야 합니다.
'개발 > C++ (98,03,11,14,17,20,23)' 카테고리의 다른 글
Modern C++ : std::exception (98, 11, 17) (0) | 2025.10.16 |
---|---|
Modern C++ : std::weak_ptr (11) (1) | 2025.10.15 |
Modern C++ : std::shared_ptr (11, 17) (0) | 2025.10.14 |
Modern C++ : std::unique_ptr (11, 14) (0) | 2025.10.13 |
Modern C++ : std::format (20) (0) | 2025.10.12 |
Modern C++ : std::ranges (20) (0) | 2025.10.11 |
Modern C++ : std::Attributes (11, 14, 17, 20) (0) | 2025.10.10 |
Modern C++ : std::any (17) (0) | 2025.09.30 |