C++11에서는 스레드를 강제로 종료하는 직접적인 메서드가 제공되지 않습니다. 이는 임의의 시점에 스레드를 강제 종료하면 리소스 누수나 데드락 같은 심각한 문제가 발생할 수 있기 때문입니다. 대신 std::promise와 std::future를 조합하면 스레드에 우아한 종료 신호를 전달할 수 있습니다.
promise와 future를 이용한 종료 신호 전달
std::future<void>를 스레드 함수에 전달하고, future에 값이 설정되면 스레드가 종료되도록 설계할 수 있습니다. 실제 값을 전달할 필요가 없고 단순히 종료 신호만 보내고 싶다면 void 타입 객체를 사용하면 됩니다.
먼저 promise 객체를 다음과 같이 생성합니다.
std::promise<void> exitSignal;
메인 함수에서 이 promise 객체로부터 연결된 future 객체를 가져옵니다.
std::future<void> futureObj = exitSignal.get_future();
스레드를 생성할 때 위에서 만든 future 객체를 함께 전달합니다.
std::thread th(&threadFunction, std::move(futureObj));
전체 예제 코드
#include <thread>
#include <iostream>
#include <assert.h>
#include <chrono>
#include <future>
using namespace std;
void threadFunction(std::future<void> future){
std::cout << "Starting the thread" << std::endl;
// future에 값이 설정될 때까지(타임아웃 동안) 반복 실행
while (future.wait_for(std::chrono::milliseconds(1)) == std::future_status::timeout){
std::cout << "Executing the thread....." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 500밀리초 대기
}
std::cout << "Thread Terminated" << std::endl;
}
main(){
std::promise<void> signal_exit; // promise 객체 생성
std::future<void> future = signal_exit.get_future(); // 연결된 future 객체 생성
std::thread my_thread(&threadFunction, std::move(future)); // 스레드 시작, future는 move로 전달
std::this_thread::sleep_for(std::chrono::seconds(7)); // 7초 대기
std::cout << "Threads will be stopped soon...." << std::endl;
signal_exit.set_value(); // promise에 값 설정 → 스레드에 종료 신호 전달
my_thread.join(); // 스레드가 끝날 때까지 대기 후 합류
std::cout << "Doing task in main function" << std::endl;
}실행 결과
Starting the thread Executing the thread..... Executing the thread..... Executing the thread..... Executing the thread..... Executing the thread..... Executing the thread..... Executing the thread..... Executing the thread..... Executing the thread..... Executing the thread..... Executing the thread..... Executing the thread..... Executing the thread..... Threads will be stopped soon.... Thread Terminated Doing task in main function
동작 원리 정리
위 예제의 흐름을 단계별로 살펴보면 다음과 같습니다.
1. 메인 함수에서 std::promise<void> 객체를 생성합니다.
2. get_future()를 호출해 promise와 연결된 future 객체를 얻습니다.
3. 스레드를 생성하면서 future 객체를 std::move로 소유권을 넘깁니다.
4. 스레드 함수 내부에서는 wait_for()가 계속 타임아웃되는 동안 작업을 반복 수행합니다.
5. 메인 함수에서 set_value()를 호출하면 future의 상태가 준비(ready)로 변경되고, 스레드의 반복문이 종료됩니다.
6. 마지막으로 join()으로 스레드가 완전히 종료된 것을 확인한 뒤 메인 함수의 나머지 작업을 진행합니다.
이 방식은 스레드가 자신의 종료 시점을 스스로 판단하게 하므로, 강제 종료 없이 안전하고 깔끔하게 스레드를 관리할 수 있는 C++11 표준적인 접근 방법입니다.