C++의 저레이턴시·병렬성 미래: std::simd, 동시성 큐, 수명 종료 포인터

📺 원본 영상: Interesting Upcoming Low-Latency, Concurrency, and Parallelism Features - CppCon 2025 🎙️ 채널: CppCon 📅 정리 일자: 2026-03-03 ⚠️ Note: 본 리포트는 영상의 음성을 텍스트로 변환(STT)하여 정리한 것입니다. 화면에 표시된 코드 슬라이드, 다이어그램 등은 포함되지 않을 수 있으며, 강연자의 구두 설명을 기반으로 재구성한 코드 예시에는 별도 표기를 하였습니다.


개요

CppCon 2025에 오른 이 세션은 IBM 출신의 세 연구자—Michael Wong, Paul McKinney, 그리고 동시성 자료구조 분야의 권위자 Maged Michael(STT 오인식 교정)—가 함께 저레이턴시, 동시성, 병렬성 영역에서 진행 중인 C++ 표준화 작업을 소개한다. 다루는 주제는 세 가지다. 첫째는 C++26에 이미 진입한 std::simd로, CPU 내부의 하드웨어 병렬성을 이식 가능한 방식으로 활용할 수 있게 한다. 둘째는 10년 가까이 표준화가 지연된 끝에 최근 급격히 진전을 이룬 동시성 큐(Proposal P0260)이다. 셋째는 2019년부터 이어져 온 오랜 여정의 마무리 단계에 있는 수명 종료 포인터(Lifetime End Pointers, 일명 ZAP) 문제로, LIFO 스택 같은 널리 쓰이는 알고리즘을 표준 C++로 합법적으로 표현하기 위한 기반이다.


std::simd — C++26이 열어주는 하드웨어 병렬성의 문

왜 지금인가: 수십 년간의 파편화된 역사

Michael Wong은 SIMD(Single Instruction, Multiple Data)의 역사를 직접 살아온 증인이다. 1997년 Intel이 MMX를 출시하고, 1999년 AltiVec(PowerPC 계열)과 SSE가 등장하면서 SIMD의 시대가 열렸다. 이후 SSE2, SSE3, SSE4, ARM의 NEON, 그리고 Intel과 AMD가 협력해 내놓은 AVX와 AVX2, 마침내 AVX-512가 잇따라 등장했고, 가장 최근에는 RISC-V의 확장 가능 벡터 명령어 세트(RVV, Scalable Vector Extension)가 128비트에서 2048비트까지 동적으로 조정 가능한 폭을 제공한다. 이처럼 SIMD는 매 세대마다 벡터 레지스터의 폭이 넓어지고 연산 능력이 강화되며 발전해 왔다.

문제는 이 풍요로운 하드웨어를 C++로 다루는 방법이 수십 년간 끔찍하게 복잡했다는 점이다. 자동 벡터화(Auto Vectorization)는 훌륭한 기술이지만 취약하고 보장이 없으며, 플랫폼별 인트린직(Intrinsic)을 직접 다루면 #ifdef로 뒤덮인 이식 불가능한 코드가 탄생한다. 강연자가 청중에게 “플랫폼별 SIMD 코드를 작성해 본 적 있는 분?”이라고 물었을 때 손이 올라갔지만, “여러 아키텍처에서 유지보수하는 것을 즐기는 분?”이라는 후속 질문에는 손이 빠르게 내려갔다는 일화가 이 고통을 압축적으로 보여준다.

핵심 타입 체계: 레인(Lane)과 마스크(Mask)

std::simd의 설계 철학은 단순하다. SIMD 객체는 여러 값을 담으며, 연산자(+, * 등)를 적용하면 해당 연산이 모든 대응 원소에 동시에 수행된다. 이 개별 원소 위치를 “레인(Lane)“이라 부른다.

💡 [영상 참조] 강연자는 이 시점에서 코드 예시 슬라이드를 보여주며 가격 배열에 세율을 곱하는 간단한 SIMD 연산을 시연합니다. 상세 코드는 원본 영상을 확인하세요.

라이브러리가 제공하는 두 가지 핵심 타입은 std::simd<T> (혹은 std::simd<T, N>)와 std::simd_mask<T>다. 전자는 T 타입의 원소를 N개 담는 벡터이며, N을 지정하지 않으면 컴파일러가 해당 타입에 가장 효율적인 네이티브 폭을 자동으로 선택한다. 후자는 비교 연산에서 생성되는 N개의 불리언 마스크로, std::simd에서 비교 연산은 단일 bool이 아닌 simd_mask를 반환한다는 점이 일반 스칼라 코드와의 핵심 차이다.

다양한 데이터 타입을 혼용할 때는 레인 수를 일치시키는 것이 필수적인데, 이를 위한 도구가 rebind_simd다. 예를 들어 float 벡터와 같은 레인 수를 가진 int 벡터를 만들려면 rebind_simd<int, simd<float>>를 사용한다. 서로 다른 폭의 벡터 간 연산은 컴파일 타임 오류로 막히므로, rebind_simd를 통해 타입 호환성을 명시적으로 확보하는 것이 올바른 설계다.

브랜치 없는 제어 흐름: simd_select

SIMD 프로그래밍에서 if 문은 함정이다. 일반적인 조건 분기는 모든 레인을 단일 경로로 강제하여 병렬성을 파괴한다. 이 문제의 해법이 바로 simd_select다. 패턴은 직관적이다. 먼저 비교 연산으로 마스크를 생성하고, simd_select(mask, true_value, false_value)를 호출한다. 이는 C++의 삼항 연산자 ? :에 정확히 대응하며, 각 레인은 마스크가 참인 경우 true_value에서, 거짓인 경우 false_value에서 값을 선택한다. 이 과정에서 코드 분기가 전혀 발생하지 않아 하드웨어의 병렬 처리가 완전히 유지된다. 강연자는 Parallelism TS(기술 명세)의 where 표현식이 혼란스럽다는 피드백을 반영해, C++26에서는 이를 훨씬 명확한 simd_select 함수로 대체했다고 강조했다.

리덕션 연산: 수직 연산 이후의 수평 집계

병렬 처리를 마친 후에는 결과를 단일 스칼라로 집계해야 하는 경우가 자주 생긴다. 이를 리덕션(Reduction) 또는 수평 연산(Horizontal Operation)이라 부른다. std::reduce(v)는 범용 집계 도구로, 기본적으로 합산을 수행한다. 내적(Dot Product) 계산이 대표적인 예다. 두 벡터를 원소별로 곱한 뒤(std::simd의 * 연산자, 즉 수직 연산), reduce를 호출해 모든 곱의 합을 하나의 스칼라로 만든다(수평 연산). 이 외에도 reduce_min과 reduce_max로 최솟값·최댓값을 구하고, 마스크에 대해서는 any_of, all_of, reduce_count로 레인 단위의 조건 분석을 수행할 수 있다.

메모리 입출력: 부분 로드와 부분 저장

실전 코드에서 데이터는 보통 std::vector나 std::span에 담겨 있다. 표준 SIMD 루프의 패턴은 벡터 폭만큼 데이터를 청크로 나눠 처리하는 것이다. 이를 위해 라이브러리는 simd_unchecked_load(전체 청크 로드), simd_partial_load(배열 끝에서 남은 원소만 안전하게 로드하고 나머지는 0으로 채움), simd_unchecked_store, simd_partial_store를 제공한다. 부분 로드·저장은 배열 경계를 벗어난 접근을 방지하는 핵심 장치다.

CMath 오버로드: 수학 함수의 SIMD 지원

이 라이브러리의 킬러 피처 중 하나는 <cmath> 전체가 std::simd 타입에 대해 오버로드된다는 점이다. sin, cos, sqrt, pow 등 모든 수학 함수가 SIMD 타입과 원소별(Element-wise)로 동작한다. 별도의 SIMD 전용 수학 라이브러리를 찾을 필요 없이, 복잡한 수식을 그대로 SIMD 타입에 적용하면 모든 레인에 동시에 연산이 수행된다.

실전 예제: 감마 보정 함수의 SIMD 구현

강연자는 이미지 감마 보정(Gamma Correction) 함수를 통해 앞서 소개한 모든 개념이 어떻게 통합되는지 보여준다. 다음은 강연 설명을 바탕으로 재구성한 코드다.

⚠️ 재구성된 코드: 아래 코드는 강연자의 구두 설명을 기반으로 재구성한 것입니다. 실제 코드는 원본 영상을 확인하세요.

#include <simd>
#include <cmath>
#include <span>
 
void gamma_correct(std::span<float> pixels, float gamma) {
    // 타입 별칭: 컴파일러가 float에 최적인 네이티브 폭을 자동 선택
    using floatv = std::simd<float>;
 
    // 스칼라 gamma 값을 모든 레인에 브로드캐스트
    const floatv v_gamma = gamma;
 
    // 데이터를 SIMD 폭만큼 청크로 순회 (i++ 대신 i += floatv::size())
    for (std::size_t i = 0; i < pixels.size(); i += floatv::size()) {
        auto pixel_subspan = pixels.subspan(i);
 
        // 배열 끝에서 남은 원소만 안전하게 로드, 나머지는 0으로 초기화
        floatv pixel_chunk = simd_partial_load<floatv>(pixel_subspan);
 
        // std::pow 오버로드: 모든 레인에 동시에 감마 보정 적용
        floatv corrected_chunk = std::pow(pixel_chunk, v_gamma);
 
        // 결과를 메모리에 안전하게 저장
        simd_partial_store(corrected_chunk, pixel_subspan);
    }
}

강연자가 강조하는 핵심은 루프 내부에 std::thread도, OpenMP 지시어도 없다는 점이다. 오직 std::pow 한 줄이 수천 픽셀의 감마 보정을 병렬로 처리한다. 코드는 읽기 쉽고, 이식 가능하며, 하드웨어 수준의 성능을 낸다.

성능 수치와 열 스로틀링 주의사항

강연자가 인용한 논문의 벤치마크에 따르면, 동일한 코드가 다양한 도메인에서 다음과 같은 속도 향상을 보인다.

도메인속도 향상
이미지 블러~5배
행렬 곱셈~5배
레이 트레이싱~6배
오디오 처리~4배

그러나 중요한 주의사항이 있다. AVX-512와 같은 광폭 SIMD 유닛은 전력 소모가 크고, 지속적으로 풀 가동하면 CPU가 열 한계를 넘어 클럭을 낮추는 열 스로틀링(Thermal Throttling)이 발생한다. 나쁜 점은 이것이 SIMD 유닛만이 아니라 CPU 전체의 클럭을 낮춘다는 것이다. 해결책은 더 좁은 벡터 폭을 요청하는 것이다. 피크 명령 처리량을 희생하고 클럭 주파수를 높게 유지하는 쪽이 전체적으로 더 나은 성능을 낼 수 있다.

CPU SIMD vs GPU SIMT: 상호보완적 도구

이 제안은 CPU 전용 기술이다. GPU 역시 하드웨어 수준에서는 SIMD 원리를 사용하지만, 그 위에 SIMT(Single Instruction Multiple Thread)라는 프로그래밍 모델을 얹는다. CPU는 소수의 강력한 코어로 레이턴시를 낮추는 데 최적화되어 있고, GPU는 수천 개의 단순한 코어로 처리량을 극대화한다. 강연자는 요리 비유로 이를 설명한다. CPU SIMD는 특수 칼(SIMD 명령어)로 동시에 당근 네 개를 써는 마스터 셰프다. GPU는 관리자(감독)가 “나사를 조여라”라고 외치면 수천 명의 작업자가 동시에 움직이는 조립 라인이다. 한 작업자에게 다른 지시를 내려야 한다면 전체 라인이 멈춰야 한다. 두 기술은 경쟁 관계가 아니라 서로 다른 문제를 푸는 도구다. GPU 프로그래밍에는 여전히 CUDA, SYCL(STT 오인식 교정: 강연자가 “CICCO”로 발음), HIP 같은 전용 프레임워크가 필요하다.


동시성 큐 (P0260) — 10년의 여정과 최근의 급진전

표준화의 긴 여정

동시성 큐(Concurrent Queue) 표준화 제안 P0260은 약 10년 전에 시작됐다. 그동안 수많은 우여곡절을 거쳤으나, 최근 1년 사이 아홉 번의 개정이 이루어질 만큼 급격히 진전했다. 이 제안은 이제 동시성 연구 그룹(SG1)과 LEWG(Library Evolution Working Group)의 인터페이스 리뷰를 통과했으며, 다음 단계인 문구 검토(Wording Review)를 앞두고 있다. C++29 혹은 그 이후의 표준에 포함될 가능성이 높아졌다는 것이 강연자의 전망이다.

동시성 큐가 표준화가 어려운 이유는 종류가 너무 많기 때문이다. 유계(Bounded)/무계(Unbounded), 단일 생산자/다중 소비자(SPMC), 다중 생산자/다중 소비자(MPMC), 대기 없음(Wait-free)/잠금 없음(Lock-free) 등 다양한 변형이 존재하고, 각각 성능과 보장의 트레이드오프가 다르다. 이 제안은 과감하게 범위를 좁혀 합의를 이끌어낸 결과물이다.

인터페이스 설계: 세 가지 개념

제안은 큐 연산을 세 가지 개념(Concept)으로 계층화한다. 첫 번째는 기본 블로킹 개념이다. push(복사/이동/인플레이스 구성 세 가지 오버로드)는 큐가 가득 찼을 때 블록하고, 성공하면 true, 큐가 닫혔으면 false를 반환한다. pop은 원소가 있으면 optional<T>를 반환하고, 큐가 비어 있을 때 블록하며, 큐가 닫히면 nullopt를 반환한다.

두 번째는 논블로킹 개념이다. try_push와 try_emplace는 queue_op_status 열거형을 반환하고, try_pop은 성공 시 expected<T, queue_op_status>를, 실패 시 상태 코드를 unexpected로 반환한다. 이 인터페이스는 블록을 절대로 허용할 수 없는 실시간 컨텍스트에서 사용한다.

세 번째는 비동기 개념이다. async_push, async_emplace, async_pop은 모두 센더(Sender)를 반환한다. 센더-리시버(Sender-Receiver) 모델에 익숙한 독자라면, 성공 시 set_value가, 큐가 닫혔을 때는 set_error가, 취소 시 set_stopped가 호출된다는 것을 이해할 것이다.

상태 열거형: 실패는 오류가 아니다

큐 상태를 표현하는 열거형은 단순해 보이지만 설계 철학이 담겨 있다. success, empty, full, closed는 직관적이다. 여기에 busy와 busy_async가 추가된다. busy는 내부 동기화가 진행 중일 때 논블로킹 연산이 반환하는 상태로, “나중에 다시 시도하라”는 신호다. busy_async는 논블로킹 연산이 비동기 작업의 스케줄링을 유발할 수 있을 때 반환되는 상태로, 이후 실행기(Executor) 인터페이스가 개선되면 제거될 예정이다.

제안이 택한 중요한 철학적 입장은 “실패는 오류가 아니다”라는 것이다. 큐가 닫혔다는 사실이 에러를 의미하지는 않는다. 따라서 닫힌 큐에서의 pop은 예외를 던지지 않고 nullopt를 반환하고, push는 false를 반환한다. 예외는 원소 타입 T의 복사·이동 생성자가 던지거나, 할당 실패(bad_alloc), 또는 하위 동기화 메커니즘(뮤텍스 등)이 교착상태를 탐지한 경우에만 발생한다.

큐 닫기(Close) 의미론

닫힌 큐는 다시 열 수 없다. 이는 단순화를 위한 의도적 선택이다. 닫힌 후에는 새 원소를 추가할 수 없지만, 이미 들어 있는 원소는 여전히 꺼낼 수 있다. 큐가 닫히는 순간, 블록 중이던 대기 중인 push와 pop 연산이 즉시 깨어나 적절한 실패 값을 반환한다.

청중 질의에서 “abort” 기능이 없는 이유가 질문됐다. 강연자는 비동기 인터페이스의 set_stopped(표준 취소 토큰 메커니즘)를 통해 동일한 효과를 달성할 수 있다고 답했다. 즉, “abort”는 센더-리시버 프레임워크의 취소 메커니즘으로 처리된다.

구체 타입: bounded_queue와 순차 일관성

표준에 포함될 구체 타입은 현재로서는 bounded_queue<T> 하나다. 생성자에서 최대 원소 수를 받으며, 이때 메모리 할당이 일어난다(이후에는 bad_alloc이 발생하지 않는다). 원소 타입 T는 이동 또는 복사 가능해야 하며, 큐 자체는 이동도 복사도 불가능하다.

메모리 순서에 대한 위원회의 결정이 흥미롭다. 고성능보다 직관성을 우선해 순차 일관성(Sequential Consistency)을 채택했다. 이 결정의 배경에는 “느슨한 메모리 순서가 직관에 어긋나는 결과를 만들 수 있다”는 논리가 있다. 두 스레드가 각각 다른 큐에 원소를 삽입하는 경우, acquire-release 순서로는 관찰 순서가 삽입 순서와 어긋날 수 있다. 강연자는 이 결정이 “고성능으로 가는 문을 닫지 않는 한” 합리적이라는 개인 의견을 덧붙였다.

논의 끝에 제외된 기능들

표준화 과정에서 합의를 저해했던 여러 기능이 제외됐다. push_front 지원, 닫힌 큐의 재개(Reopen), 엄밀한 이론적 의미에서의 잠금 없음(Lock-free) 보장, 스트리밍 이터레이터(한 큐에서 다른 큐로 원소를 이동), 정지 상태(Quiescent State)의 원소 순회, 큐에 이름 부여 등이 모두 제외됐다. 이는 “완벽한 것”을 기다리다가 아무것도 표준화하지 못하는 상황을 피하기 위한 현실적 선택이다.


수명 종료 포인터와 ZAP — LIFO 스택을 표준 C++로 쓸 수 있게

포인터 무효화란 무엇인가

Paul McKinney는 어셈블리 언어부터 프로그래밍을 시작한 사람조차 충격받는 개념에서 출발한다. 객체가 delete되는 순간, 그 객체를 가리키던 모든 포인터가 즉시 무효화(Invalidated)된다는 것이다. 이 무효화는 포인터의 비트(Bit)가 변하는 것이 아니다. 컴파일러가 별도로 추적하는 메타정보, 즉 “이 포인터가 어떤 new 호출에서 비롯됐는가”를 나타내는 **프로비넌스(Provenance)**가 사라진다는 의미다.

프로비넌스의 실질적 효과를 예로 들면, 포인터 p를 delete하고 같은 주소에 q를 new로 할당했을 때, p == q를 비교하면 컴파일러는 “이 두 포인터는 서로 다른 new 호출에서 비롯됐으므로 같을 수 없다”고 결론짓고 false를 반환할 수 있다. 실제 비트는 동일하더라도 말이다. 무효화된 포인터에 대한 모든 연산—비교, 역참조(Dereference)뿐 아니라 단순 로드와 저장조차도—은 표준에서 “구현 정의(Implementation-Defined)” 또는 미정의 동작(Undefined Behavior)으로 처리된다. 이 규칙이 1989년 C 표준부터 존재했던 이유는 컴파일러의 앨리어싱 분석과 포인터 해석 최적화를 가능하게 하기 위해서였다.

LIFO 푸시 알고리즘과 좀비 포인터 문제

이 개념이 동시성 프로그래밍과 충돌하는 대표적인 예가 LIFO 스택 알고리즘이다. 이 알고리즘은 1973년 특허에서 이미 확인될 만큼 오래됐다. 구조는 단순하다. 연결 리스트의 헤드를 원자 포인터로 유지하고, push는 비교-교환(Compare-and-Exchange, CAS) 루프로 새 원소를 리스트 앞에 연결하며, pop_all은 헤드를 원자적으로 nullptr로 교환해 전체 리스트를 한 번에 꺼내는 작업이다.

💡 [영상 참조] 강연자는 이 시점에서 화이트보드 다이어그램을 사용해 두 태스크가 동시에 실행될 때 좀비 포인터가 생성되는 과정을 단계별로 시연합니다. 상세 내용은 원본 영상을 확인하세요.

문제는 다음과 같은 시나리오에서 발생한다. 태스크 1이 CAS 연산을 준비하는 사이, 태스크 2가 pop_all로 리스트를 통째로 꺼내고, 해제한 메모리를 새 원소 D로 재할당한다. 이때 원소 D가 태스크 1이 준비한 포인터와 같은 주소를 가지게 된다. CAS는 비트 수준에서만 비교하므로 태스크 1의 CAS가 성공하지만, 태스크 1의 next 포인터는 이미 해제된 메모리를 가리키는 **좀비 포인터(Zombie Pointer)**가 된다. 이 좀비 포인터가 스택에 연결되면, 이후 pop_all을 호출하는 스레드는 유효하지 않은 포인터를 역참조하게 된다. 어셈블리 언어로는 완벽히 유효하지만, C++ 표준으로는 정의되지 않은 동작이다.

세 논문의 조합으로 문제 해결

CppCon 2019 이후 오랫동안 진행된 이 작업은 세 가지 논문의 조합으로 LIFO 스택 알고리즘을 소스 코드 수정 없이 표준 C++에서 합법적으로 표현하는 것을 목표로 한다.

첫 번째는 Davis Herring의 제안에 기반한 것으로, 포인터를 정수로 변환했다가 다시 포인터로 변환하는 관용구가 이미 허용되어 있다는 데 착안한다. 이 변환은 “컴파일러가 해당 주소에 현재 존재하는 (혹은 변환 연산과 동시에 생성되는) 객체를 선택한다”는 의미를 갖는다. Davis의 제안은 이 선택 범위를 확장해, “동시에 생성된 객체”도 포함하도록 한다. 이에 더해 atomic 변수와 volatile 변수가 포인터의 정수 변환과 유사한 의미론(프로비넌스를 초기화)을 갖도록 하는 것이 요청이다. CAS의 성공 케이스에서 참조로 전달된 구 포인터(Old Value) 역시 컴파일러가 프로비넌스 정보를 잊도록 요구한다.

두 번째 논문은 무효 포인터에 대한 구현 정의 동작을 “타이트하게” 만드는 것이다. 비교, 산술, 역참조를 제외한 단순 로드와 저장 연산에 대해서는, 포인터가 무효하더라도 동일한 비트 값을 반환하도록 보장을 요구한다. 이 보장이 있어야 무효 포인터를 atomic_load나 atomic_store의 인자로 전달하는 행위가 정의된 동작이 된다.

세 번째 논문은 동시성이 없는 디버깅 용도를 위한 것이다. 해제된 포인터를 해시 맵의 키로 사용하는 등의 디버깅 기법을 표준 C++으로 표현하기 위해, 프로비넌스를 의도적으로 무시하는 launder_pointer_bits 함수와 pointer_bits<T> 템플릿 클래스를 추가하는 것이 제안이다. 이를 통해 포인터의 비트만을 추적하고 유효성 정보를 배제할 수 있게 된다.

표준화 전망

세 논문이 모두 채택된다면, LIFO 스택 알고리즘은 소스 코드 변경 없이 유효한 C++로 인정된다. 강연자는 이 알고리즘이 전 세계 코드베이스에 “무의식중에 재발명된 형태로” 수없이 박혀 있다고 강조했다. 이를 모두 찾아 고치는 것이 불가능하기 때문에, 언어 표준이 이 자연스러운 작성 방식을 수용해야 한다는 것이 그의 주장이다. 2019년 CppCon 첫 발표 이후 처음에는 더 공격적인 접근이 시도됐다가 반려됐고, 현재의 방향으로 다시 진행 중이다. 목표는 C++29이며, 강연자는 “낙관적이다”고 말했다.


마무리: C++의 미래가 세 방향에서 오고 있다

세 강연자가 소개한 주제는 각기 다른 시간대에 있지만, 공통된 방향성을 가리킨다. C++가 현대 하드웨어의 능력을 더욱 안전하고 이식 가능한 방식으로 표현할 수 있는 언어로 진화하고 있다는 것이다.

std::simd는 C++26의 확정 피처로, 오늘부터 쓸 수 있다. 수십 년간 #ifdef 지옥 속에 갇혀 있던 CPU 하드웨어 병렬성을 표준 C++의 품 안으로 가져왔다는 것은 작은 변화가 아니다. 동시성 큐는 10년의 여정 끝에 합의 가능한 범위로 좁혀진 제안을 들고 C++29를 향해 가고 있다. 순차 일관성이라는 보수적 선택은 “완벽한 성능”보다 “일단 표준에 들어가는 것”을 택한 현실적 결정이다. 그리고 수명 종료 포인터 문제는 C++에 동시성이 생기는 순간부터 존재했던 오래된 부채를 청산하는 작업이다. LIFO 스택 하나를 합법적으로 쓰기 위해 세 편의 논문이 필요하다는 사실은 C++ 표준의 복잡성을 웅변하지만, 그 끝이 보인다는 점에서 의미 있는 진전이다.


📚 출처 및 참고

구분내용
원본 영상Interesting Upcoming Low-Latency, Concurrency, and Parallelism Features - CppCon 2025
채널CppCon
발표자Michael Wong, Maged Michael, Paul McKinney
리포트 작성2026-03-03
작성 방식YouTube 영상 STT 변환 후 에디팅

💬 본 리포트는 영상 내용을 바탕으로 재구성되었습니다. 정확한 내용은 원본 영상을 참조해 주세요.


📎 관련 표준 문서 (강연에서 언급된 것, 직접 링크 미제공)

강연자들이 직접 언급한 주요 제안 문서들은 다음과 같다. 이는 강연 내용 기반으로 정리된 것이며, 실제 문서는 WG21(ISO C++ 위원회) 공식 문서 저장소에서 확인할 수 있다.

std::simd는 Parallelism TS 2를 거쳐 C++26에 포함됐다. 동시성 큐는 P0260이 핵심 제안으로, 최근 9번의 개정을 통해 SG1과 LEWG를 통과했다. 수명 종료 포인터 관련해서는 세 논문이 언급됐다 — Davis Herring의 포인터-정수 변환 의미론 확장 제안, 무효 포인터의 로드·저장에 대한 구현 정의 동작 타이트닝 제안(P2414 및 관련 분리 논문들), 그리고 launder_pointer_bits와 pointer_bits 템플릿 추가 제안이다. P0387은 동시성 큐의 메모리 순서 결정 근거로 인용됐다.