26. std::async / std::future / std::promise 내부 동작과 launch policy, 예외 전파
난이도 상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C++
// 문제 26 — std::async / std::future / std::promise 내부 동작:
// launch policy와 예외 전파
//
// 아래는 게임 서버에서 여러 비동기 작업(랭킹 계산, 리더보드 갱신, 검증)을
// std::async로 실행하는 코드다. launch policy를 서로 다르게 지정한 태스크들과,
// 태스크 내부에서 예외를 던지는 경우를 섞어 두었다.
//
// (A) task_deferred는 std::launch::deferred 정책으로 생성된다.
// (B) task_async는 std::launch::async 정책으로 생성된다.
// (C) task_throw는 std::launch::async 정책이며 내부에서 예외를 던진다.
// (D) task_unused는 future를 받아두기만 하고 get()을 호출하지 않는다.
//
// 과제:
// 1. 아래 프로그램을 실행하면 콘솔에 어떤 순서로 로그가 출력되는지 예측하라.
// 특히 "[deferred] 실행됨"이 언제(메인 스레드의 어느 줄이 실행된 직후)
// 출력되는지 정확히 짚어라.
// 2. task_throw.get() 을 호출하는 지점에서 무슨 일이 벌어지는지 예측하라
// (프로그램이 어떻게 종료되는가, 어떤 예외 타입이 잡히는가).
// 3. task_deferred의 future를 한 번도 get()/wait() 하지 않고 프로그램이
// 끝난다면 "[deferred] 실행됨" 로그가 출력되는지 예측하라.
// 4. task_unused (std::launch::async 정책)의 future가 지역 변수 스코프를
// 벗어나 소멸될 때 무슨 일이 일어나는지 예측하라(스레드가 즉시 백그라운드로
// 떨어져 나가는지, 아니면 소멸자가 태스크 완료를 기다리는지).
// 5. std::future_status를 사용해 task_async의 완료 여부를 폴링하는
// wait_for 호출 결과가 어떻게 나오는지 예측하라.
//
// 아래 코드는 그대로 컴파일·실행 가능하다 (g++ -std=c++17 -pthread).
#include <future>
#include <iostream>
#include <chrono>
#include <stdexcept>
#include <thread>
int SlowCompute(int base_value) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::cout << "[async] 실행됨 (base=" << base_value << ")\n";
return base_value * 2;
}
int DeferredCompute(int base_value) {
std::cout << "[deferred] 실행됨 (base=" << base_value << ")\n";
return base_value + 100;
}
int ThrowingCompute() {
std::this_thread::sleep_for(std::chrono::milliseconds(20));
std::cout << "[throw-task] 실행됨, 곧 예외를 던짐\n";
throw std::runtime_error("랭킹 계산 실패: 데이터 손상");
}
int main() {
std::cout << "[main] 태스크 생성 시작\n";
std::future<int> task_deferred = std::async(std::launch::deferred, DeferredCompute, 1);
std::future<int> task_async = std::async(std::launch::async, SlowCompute, 10);
std::future<int> task_throw = std::async(std::launch::async, ThrowingCompute);
{
// task_unused: async 정책으로 실행되지만 get()을 호출하지 않고
// 이 블록을 벗어나면서 future가 소멸된다.
std::future<int> task_unused = std::async(std::launch::async, SlowCompute, 999);
std::cout << "[main] task_unused 스코프 종료 직전\n";
}
std::cout << "[main] task_unused 스코프 종료 직후 (future 소멸됨)\n";
std::cout << "[main] task_async 폴링 시작\n";
auto status = task_async.wait_for(std::chrono::milliseconds(0));
std::cout << "[main] 폴링 결과: "
<< (status == std::future_status::ready ? "ready"
: status == std::future_status::timeout ? "timeout"
: "deferred")
<< "\n";
std::cout << "[main] task_deferred.get() 호출 직전\n";
int deferred_result = task_deferred.get();
std::cout << "[main] task_deferred 결과 = " << deferred_result << "\n";
std::cout << "[main] task_async.get() 호출 직전\n";
int async_result = task_async.get();
std::cout << "[main] task_async 결과 = " << async_result << "\n";
std::cout << "[main] task_throw.get() 호출 직전\n";
try {
int throw_result = task_throw.get();
std::cout << "[main] task_throw 결과 = " << throw_result << "\n";
} catch (const std::exception& e) {
std::cout << "[main] task_throw.get()에서 예외 포착: " << e.what() << "\n";
}
std::cout << "[main] 종료\n";
return 0;
} 내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.