[C++23 새기능 소개] std::in_place_stop_source와 std::in_place_stop_token

C++23에서는 비동기 프로그래밍과 스레드 관리 패턴을 한층 더 간단하고 효율적으로 만들기 위해 std::in_place_stop_sourcestd::in_place_stop_token이 도입되었습니다. 이들은 C++20에서 도입된 std::stop_source와 std::stop_token을 개선한 것으로, 비동기 작업이나 스레드 실행을 안전하고 직관적으로 중단(stop)할 수 있는 메커니즘을 제공합니다.

기존의 std::stop_source/std::stop_token과 달리, in_place 버전은 무상태(stateless)로, 저장 비용이 줄고 더 가벼우며, 기본적으로 커스텀 메모리 관리나 동기화 없이도 안전하게 중단 신호를 전달하고 처리할 수 있습니다.

이번 글에서는 std::in_place_stop_source와 std::in_place_stop_token의 개념과 사용법, 그리고 이전 방식과 비교하여 어떠한 개선점을 제공하는지 알아보겠습니다.

 

std::in_place_stop_source와 std::in_place_stop_token란 무엇인가요?

  • std::in_place_stop_source: 중단 신호를 발행(stop request)할 수 있는 소스 역할을 하는 객체입니다. request_stop()를 호출하면 연관된 std::in_place_stop_token에 중단 신호가 전달됩니다.
  • std::in_place_stop_token: in_place_stop_source와 연계되어 중단 여부를 확인할 수 있는 토큰 객체입니다. stop_requested()를 통해 중단 신호가 도착했는지 검사할 수 있습니다.

in_place 버전은 C++20의 std::stop_source/std::stop_token 대비 추가 상태를 갖지 않거나 훨씬 경량화되어 있어, 더욱 가볍고 이식성 있는 중단 메커니즘을 제공합니다.

이전 버전에서는 어떻게 했나요?

C++20에서는 std::stop_source와 std::stop_token을 도입하여 스레드나 비동기 작업을 정지시키는 표준화된 방법을 제공했습니다. 그러나 이들은 내부적으로 상태를 관리하는데, 경우에 따라 추가 상태나 동기화 비용이 들 수 있었습니다. 또한 단순히 중단 신호만 필요할 때 in_place 버전이 더 효율적인 경우가 존재합니다.

예제: 기존 방식(C++20)

#include <stop_token>
#include <thread>
#include <iostream>

void work_function(std::stop_token st) {
    while (!st.stop_requested()) {
        // 작업 수행
    }
    std::cout << "작업 종료!\n";
}

int main() {
    std::stop_source src;
    std::jthread th(work_function, src.get_token());

    // 필요 시 중단 요청
    src.request_stop();
    return 0;
}
  • 기존에도 가능했으나, stop_source/stop_token은 내부 상태를 갖고, 더 무거운 경우가 있을 수 있습니다.

C++23의 std::in_place_stop_source 사용 예제

#include <stop_token>
#include <thread>
#include <iostream>

void work_function(std::in_place_stop_token st) {
    while (!st.stop_requested()) {
        // 작업 수행
    }
    std::cout << "작업 종료!\n";
}

int main() {
    std::in_place_stop_source src;
    std::jthread th(work_function, src.get_token());

    // 필요 시 중단 요청
    src.request_stop();
    return 0;
}
  • in_place_stop_source와 in_place_stop_token을 사용하면 비슷한 방식으로 중단 로직을 구현할 수 있으나, 더 경량화되고 효율적일 수 있습니다.

어떻게 좋아졌나요?

  • 경량화: in_place_stop_source/in_place_stop_token은 최소한의 상태만 관리하므로, 기존 stop_source/stop_token 대비 더 가벼울 수 있음.
  • 간결한 코드: 사용법은 stop_source/stop_token와 거의 동일하지만, 필요 없는 상태 관리나 동기화가 줄어들어 성능 및 단순성 향상.
  • 이식성과 효율성: 복잡한 쓰레드 취소나 외부 라이브러리 의존 없이 표준화된 방식으로 비동기 작업 정지 구현 가능.

다른 예제

#include <stop_token>
#include <vector>
#include <algorithm>
#include <iostream>

void processData(std::in_place_stop_token st, const std::vector<int>& data) {
    for (int x : data) {
        if (st.stop_requested()) break;
        // 데이터 처리 로직
    }
    std::cout << "데이터 처리 종료!\n";
}

int main() {
    std::in_place_stop_source src;

    std::jthread worker([&]{
        std::vector<int> data = {1,2,3,4,5,6,7,8,9,10};
        processData(src.get_token(), data);
    });

    // 잠시 후 작업 중단 요청
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    src.request_stop(); 

    // worker 스레드 조인 (jthread는 자동 조인)
    return 0;
}
  • in_place_stop_token를 통해 간단히 중단 신호를 체크, 불필요한 추가 상태나 동기화 부담 감소.

주의 사항

  • C++23 지원 여부: 이 기능은 C++23이 필요, 지원하는 컴파일러 및 라이브러리 필요.
  • stop_requested 체크 로직: 주기적으로 stop_requested()를 확인하는 로직은 여전히 개발자가 적절히 삽입해야 함.
  • 성능 상 이점: 실제 성능 개선 정도는 구현체에 따라 다를 수 있으므로, 필요하다면 성능 측정 필요.

요약

C++23의 std::in_place_stop_source와 std::in_place_stop_token은 비동기 작업 중단 로직을 더욱 단순하고 가볍게 만들기 위해 추가된 기능입니다. 기존의 stop_source/stop_token 대비 상태와 오버헤드를 줄여, 비동기 프로그래밍 시 코드 가독성과 성능을 향상시키며, 복잡한 쓰레드 취소 메커니즘 없이도 안전하고 직관적인 중단 신호 전달이 가능합니다.

 

참고 자료:

반응형