C++23에서는 비동기 프로그래밍과 스레드 관리 패턴을 한층 더 간단하고 효율적으로 만들기 위해 std::in_place_stop_source와 std::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 대비 상태와 오버헤드를 줄여, 비동기 프로그래밍 시 코드 가독성과 성능을 향상시키며, 복잡한 쓰레드 취소 메커니즘 없이도 안전하고 직관적인 중단 신호 전달이 가능합니다.
참고 자료:
'개발 이야기 > C++' 카테고리의 다른 글
[모던 C++ #1] 이제는 버려야 할 레거시: auto_ptr를 내려놓고 unique_ptr로! (0) | 2024.12.14 |
---|---|
[C++23 새기능 소개] std::ranges::sample (0) | 2024.12.12 |
[C++23 새기능 소개] std::views::repeat와 std::views::repeat_n (1) | 2024.12.12 |
[C++23 새기능 소개] std::views::common (0) | 2024.12.12 |
[C++23 새기능 소개] std::ranges::drop_last, std::ranges::drop_last_while (1) | 2024.12.12 |