C++ 비동기 프로그래밍

C++ 비동기 프로그래밍

1. 비동기 프로그래밍의 이해

C++ 비동기 프로그래밍은 현대 소프트웨어 개발에서 응답성, 효율성, 확장성을 확보하는 데 필수적인 패러다임으로 자리매김하였다. 본 안내서는 비동기 프로그래밍의 근간이 되는 개념들을 명확히 정의하고, 현대 C++ 개발 환경에서 그 중요성을 심도 있게 논한다.

1.1 동기(Synchronous)와 비동기(Asynchronous)의 개념 정의

동기 방식은 요청과 그 결과가 동시에 발생하는 특성을 지닌다. 즉, 함수를 호출하면 그 결과가 반환될 때까지 호출한 측은 대기 상태에 머무른다.1 이는 순차적이며 예측 가능한 코드 흐름을 제공하지만, 장시간 소요되는 작업이 발생할 경우 전체 프로그램의 진행을 멈추게 하는 ‘블로킹’ 현상을 야기할 수 있다.1

반면, 비동기 방식은 요청과 그 결과가 동시에 발생하지 않는다는 점에서 동기 방식과 명확히 구분된다. 함수를 호출한 측은 수행 결과를 직접 처리하지 않고 콜백 함수와 같은 메커니즘을 통해 결과를 전달받으며, 호출 즉시 제어권을 반환하여 다른 작업을 수행할 수 있도록 한다.1

1.2 블로킹(Blocking)과 논블로킹(Non-blocking)의 차이

블로킹 방식은 자신의 수행 결과가 완료될 때까지 제어권을 독점하여, 호출한 측이 다른 작업을 수행할 수 없도록 제약을 가한다.1 예를 들어, 사용자 입력이 완료될 때까지 프로그램이 어떠한 동작도 수행하지 않는 경우가 이에 해당한다.1

논블로킹 방식은 자신이 호출되었을 때 제어권을 즉시 호출한 측으로 넘겨, 호출한 측이 다른 작업을 병행할 수 있도록 허용한다.1 비동기 프로그래밍은 본질적으로 논블로킹 아키텍처를 지향하며, 이는 여러 관련 작업이 다른 작업의 완료를 기다리지 않고 동시에 실행될 수 있도록 한다.3

1.3 현대 C++ 개발에서 비동기 프로그래밍의 중요성

비동기 프로그래밍은 현대 소프트웨어의 핵심 요구사항인 응답성, 효율성, 확장성을 충족시키는 데 결정적인 역할을 수행한다. 입출력(I/O) 작업, 네트워크 요청, 데이터베이스 쿼리 등 시간이 오래 걸리는 작업들을 백그라운드에서 처리함으로써, 메인 스레드가 블로킹되는 것을 방지하고 사용자 인터페이스(UI)가 지속적으로 반응하도록 보장한다.4 이는 사용자 경험(UX)을 크게 향상시키는 직접적인 결과를 가져온다.5

또한, 블로킹 시간 동안 중앙 처리 장치(CPU)가 유휴 상태에 머무르지 않고 다른 유용한 작업을 수행할 수 있게 하여 시스템 자원 활용도를 극대화한다.5 여러 작업을 동시에 처리함으로써 대용량 트래픽 처리나 대규모 시스템 구축에 유리하며, 시스템의 처리량(throughput)을 향상시키는 기반을 제공한다.5 멀티코어 CPU 환경에서는 여러 작업을 동시에 실행하여 성능을 극대화할 수 있는 병렬성 활용의 중요한 기반이 된다.7

비동기 패러다임은 단순히 기술적 선택을 넘어, 현대 소프트웨어가 사용자 기대와 하드웨어 잠재력을 충족하기 위한 필수적인 설계 철학의 변화를 의미한다. 동기 프로그래밍이 ’한 번에 하나의 작업’에 집중하는 ‘단일 트랙’ 사고방식이라면 5, 비동기 프로그래밍은 ’여러 작업을 동시에 진행’하는 ‘멀티태스커’ 사고방식으로의 전환이다.5 이러한 전환은 코드의 복잡성을 증가시키지만 2, 얻는 이점이 훨씬 크다. 과거의 “프로스팅된 창” (응답 없는 UI)과 “회전하는 도넛” (로딩 아이콘) 현상을 과거의 유물로 만들 수 있다고 언급되는 것은 10, 비동기 프로그래밍이 단순한 개발 기법을 넘어 사용자 경험의 질을 근본적으로 변화시키는 핵심 요소임을 시사한다.

1.4 표 1: 동기 vs. 비동기 프로그래밍 비교

측면동기(Synchronous)비동기(Asynchronous)
실행 순서순차적, 한 번에 하나씩동시적, 여러 작업 병렬 실행 가능
블로킹작업 완료까지 블로킹논블로킹, 다른 작업 계속 실행
성능 특성I/O 작업에 느림I/O 집약적 작업에 빠름, 처리량 향상
복잡성구현이 단순함로직이 더 복잡함 (콜백, Promise/Future, Coroutine)
주요 활용순서가 중요한 작업, 간단한 로직응답성 UI, 네트워크 통신, 대규모 데이터 처리, 게임 엔진
자원 활용CPU 유휴 시간 발생 가능CPU 유휴 시간 최소화, 자원 효율성 증대
사용자 경험작업 대기 발생 가능, 응답성 저하빠르고 끊김 없는 흐름, 응답성 향상
디버깅비교적 단순함비선형적 특성으로 인해 더 복잡함

2. C++ 표준 라이브러리의 비동기 기능

C++11부터 표준 라이브러리는 동시성 및 비동기 프로그래밍을 위한 강력한 도구들을 제공하기 시작하였다. 이 섹션에서는 주요 표준 라이브러리 기능들을 상세히 분석한다.

2.1 std::thread와 그 한계

std::thread는 새로운 실행 스레드를 생성하여 함수를 병렬적으로 실행할 수 있게 하는 기본적인 도구이다.17 이는 계산 집약적인 작업, 즉 CPU 바운드(CPU-bound) 작업을 여러 코어에 분산하여 처리하는 데 특히 유용하다.6

그러나 std::thread를 직접 사용하는 것은 여러 가지 문제점을 내포한다. 스레드 생성 및 소멸에 따른 비용, 빈번한 컨텍스트 스위칭으로 인한 오버헤드, 그리고 복잡한 동시성 제어(경쟁 조건, 교착 상태 등) 문제가 발생하기 쉽다.13 특히 스레드 수가 과도하게 많아지면(예: 프로세서당 100개 이상) 컨텍스트 스위칭 오버헤드와 공유 자원 경합으로 인해 오히려 성능이 저하될 수 있다.13 또한, std::thread는 함수의 반환 값을 직접 처리하기 어렵고, 예외 처리 메커니즘이 부족하다는 한계가 지적된다.22

2.2 std::promisestd::future: 비동기 결과 전달의 약속

std::promise는 비동기적으로 수행될 작업의 결과를 설정하는 객체이며, std::future는 그 결과를 나중에 받아올 수 있는 ‘약속’ 또는 ’미래의 값’을 나타내는 객체이다.17 이 두 객체는 비동기 작업의 완료를 알리고 결과를 전달하는 데 사용되는 중요한 동기화 지점을 제공한다.26

std::promiseset_value() 메서드를 통해 작업의 최종 값을 설정하거나, set_exception()을 통해 발생한 예외를 전달할 수 있다.26

std::futureget() 함수를 통해 약속된 데이터를 얻을 수 있으며, 이 함수는 데이터가 준비될 때까지 호출 스레드를 블로킹하는 특성이 있다.23

wait() 함수는 데이터가 준비될 때까지 기다리지만 값을 반환하지 않으며, wait_for() 함수는 지정된 시간 동안만 기다리거나 비동기 작업의 상태를 확인하는 데 사용된다.23

std::shared_futurestd::future와 달리 여러 스레드가 동일한 공유 상태를 기다리는 것을 허용하여, 하나의 비동기 작업 결과를 여러 곳에서 동시에 사용할 수 있게 한다.28

2.3 std::packaged_task: 함수 객체 비동기 실행

std::packaged_task는 함수 자체를 캡슐화하여 비동기적으로 실행할 수 있도록 ’포장’하는 특수한 함수 객체이다.17 이는 생성자의 인자로 실행할 함수를 받고, 해당 함수의 리턴 타입과 파라미터 타입을 템플릿 인자로 명시해야 한다.23

std::packaged_taskget_future() 메서드를 통해 std::future 객체를 반환하여 비동기 작업의 결과를 얻을 수 있게 한다.17 실제 실행은 std::thread에 의해 수행될 수 있으며 17, 이를 통해 특정 함수를 스레드에서 실행하고 그 결과를 future로 편리하게 받을 수 있는 구조를 제공한다.

2.4 std::async: 편리한 비동기 작업 시작 및 실행 정책

std::async는 함수를 비동기적으로 실행하고 그 결과값을 보관할 std::future를 반환하는 가장 편리한 방법 중 하나이다.17 std::thread보다 안정적이며 프로그래머가 사용하기 편리한 기능으로 일반적으로 권장된다.22 std::async는 비동기 작업의 실행 방식을 제어하는 std::launch 정책을 인자로 받을 수 있다.17

std::launch::async 정책은 새로운 스레드를 즉시 생성하여 인자로 전달된 함수를 비동기적으로 실행하도록 지시한다.17 하지만 표준은 이것이 반드시 새로운 스레드를 생성할 것을 보장하지는 않으며 20, 일부 구현에서는 스레드 풀을 사용할 수도 있다.20

std::launch::deferred 정책은 std::future 객체의 get() 또는 wait() 함수가 호출될 때까지 함수의 실행을 지연시키며, 새로운 스레드를 생성하지 않고 호출 스레드에서 동기적으로 실행된다.17 이 지연 실행은 개발자가 예상치 못한 동작을 유발할 수 있으므로 주의가 필요하다.32 정책을 명시하지 않는 기본 동작의 경우, 런타임 라이브러리가 스레드를 시작할지, 아니면 get() 또는 wait()를 호출한 스레드에서 작업을 실행할지 선택한다.28 이 경우 비동기 실행 여부를 예측하기 어렵고, 스레드 로컬 변수 사용에 문제가 발생할 수 있다.32

std::async는 편리하지만 한계도 존재한다. 함수 내부에서 std::async를 사용할 경우, 결과값을 받아오기 전까지 함수를 빠져나갈 수 없어 메인 스레드와 진정한 비동기적 운용이 어려울 수 있다는 지적이 있다.34 또한, std::future의 소멸자가 작업 완료를 기다리도록 되어 있어, 의도치 않게 호출 스레드를 블로킹하여 비동기성을 저해할 수 있다.20

2.5 동기화 기본 요소: 뮤텍스, 조건 변수, 아토믹의 역할

비동기 및 다중 스레드 환경에서는 여러 실행 흐름이 공유 자원에 동시에 접근하여 읽기/쓰기 작업을 수행할 때 **경쟁 조건(Race Condition)**이 발생할 수 있다.7 이는 실행 순서가 보장되지 않아 결과의 일관성이 훼손되는 상황을 초래하며, 디버깅하기 매우 어려운 비결정적 버그의 주된 원인이 된다.36 이러한 문제를 방지하기 위해 동기화 메커니즘은 필수적이다.17

  • std::mutex 및 락 가드: std::mutex는 상호 배제(Mutual Exclusion)를 제공하는 가장 기본적인 동기화 프리미티브이다. 공유 변수에 대한 경쟁 조건이 발생하는 임계 영역(critical section)을 보호하며, lock()unlock() 연산을 통해 오직 하나의 스레드만 해당 영역에 접근하도록 제어한다.17

std::lock_guardstd::unique_lock, 그리고 C++17에서 도입된 std::scoped_lock은 RAII(Resource Acquisition Is Initialization) 기법을 활용하여 뮤텍스 잠금 및 해제를 자동화하고 예외 안전성을 보장한다.17 특히 std::scoped_lock은 여러 뮤텍스를 동시에 안전하게 잠가 교착 상태를 회피하는 데 도움을 준다.41

  • std::condition_variable: 스레드들이 특정 조건이 충족될 때까지 효율적으로 대기하거나, 조건이 충족되었음을 다른 스레드에 알리는 데 사용된다.17 이는 생산자-소비자(Producer-Consumer) 패턴과 같은 복잡한 동시성 시나리오 구현에 핵심적으로 활용된다.40

  • std::atomic: 락-프리(lock-free) 동기화를 제공하여 간단한 데이터 타입에 대한 안전한 동시 수정을 가능하게 한다.17 이는 뮤텍스나 락의 오버헤드 없이 공유 데이터를 조작할 수 있는 이점을 제공한다.

이러한 동기화 프리미티브는 비동기 프로그래밍의 ’양날의 검’과 같다. 비동기 작업의 핵심인 ’동시성’을 가능하게 하지만, 잘못 사용하면 경쟁 조건과 교착 상태라는 더 큰 문제를 야기할 수 있다.7 따라서 이들 도구의 올바른 이해와 적용이 비동기 프로그래밍의 성공 여부를 결정하는 중요한 요소임을 강조한다.

2.6 표 2: C++ 동시성 모델 비교: std::thread vs. std::async vs. C++20 코루틴

측면std::threadstd::asyncC++20 코루틴
생성 비용높음 (OS 스레드 생성)비교적 낮음 (런타임 결정, 스레드 풀 가능)매우 낮음 (사용자 공간 스케줄링, 스택리스)
스케줄링 방식OS 커널에 의한 선점적 스케줄링런타임 라이브러리 결정 (OS 스레드 또는 지연 실행)프로그래머에 의한 협력적 스케줄링
메모리 사용량높음 (각 스레드 고유 스택)중간 (스레드 생성 시 스택 사용)매우 낮음 (힙에 코루틴 상태 저장)
예외 처리직접 구현 필요, 복잡함std::future를 통해 예외 전달 가능promise 객체 및 try-catch로 처리, 구조화됨
반환 값 처리직접 처리 어려움std::future로 편리하게 반환 값 획득co_returnpromise 객체로 처리
적합한 사용 사례CPU 바운드 작업, 명시적 스레드 관리 필요 시간단한 비동기 작업, I/O 바운드 작업I/O 바운드 작업, 경량 동시성, 콜백 지옥 해소
동기화 문제경쟁 조건, 교착 상태 발생 가능성 높음경쟁 조건, 교착 상태 발생 가능성 있음단일 스레드 내 동시성으로 동기화 문제 완화
코드 가독성복잡한 동시성 로직으로 가독성 저하 가능성future 사용으로 개선되나, 지연 실행 등 주의 필요동기 코드처럼 비동기 로직 작성 가능, 가독성 우수

3. C++20 코루틴: 비동기 프로그래밍의 새로운 지평

C++20에 도입된 코루틴은 비동기 프로그래밍 패러다임에 혁명적인 변화를 가져왔다. 이 섹션에서는 코루틴의 개념, 핵심 키워드, 그리고 기존 방식과의 비교를 통해 그 잠재력을 조명한다.

3.1 코루틴 개념 및 특징: 스택리스(Stackless)와 협력적 멀티태스킹

코루틴은 실행을 일시 중단하고 나중에 재개할 수 있는 함수를 일반화한 것이다.44 일반 함수는 호출되고 완료될 때까지 실행되지만, 코루틴은 중간에 제어권을 호출자에게 양보하고 나중에 중단된 지점부터 다시 실행을 재개할 수 있다.45

C++20 코루틴은 스택리스(Stackless) 방식으로 구현된다. 이는 실행에 필요한 데이터(promise 객체, 매개변수 복사본, 현재 중단 지점 정보 등)가 스택과 별도로 동적으로 할당된 ‘코루틴 상태(Coroutine State)’ 또는 ’코루틴 프레임(Coroutine Frame)’에 저장됨을 의미한다.44 이를 통해 코루틴은 호출자에게 제어권을 반환하면서 실행을 중단할 수 있다.46

또한, 코루틴은 협력적 멀티태스킹(Cooperative Multitasking) 모델을 따른다. 운영체제 커널에 의해 선점적으로 스케줄링되는 스레드와 달리, 코루틴은 프로그래머가 co_awaitco_yield와 같은 키워드를 통해 명시적으로 제어권을 양보할 때만 중단된다.19 이는 사용자 공간에서 스케줄링되어 컨텍스트 스위칭 오버헤드가 훨씬 적고 21, 경량의 동시성 처리에 유리하다.49

3.2 co_await, co_yield, co_return 키워드의 활용

함수 내부에 co_await, co_yield, co_return 중 하나라도 포함되면 해당 함수는 코루틴으로 간주된다.44

  • co_await: 비동기 작업이 완료될 때까지 코루틴의 실행을 일시 중단한다.44 이는 I/O 작업이나 네트워크 요청과 같이 대기 시간이 긴 작업에 특히 유용하며, 코루틴이 대기하는 동안 메인 스레드가 다른 작업을 수행할 수 있도록 한다.47

await_ready, await_suspend, await_resume 세 가지 메서드를 구현하는 Awaiter 객체와 함께 사용되어 비동기 작업의 완료 여부, 일시 중단 및 재개 로직을 정의한다.47

  • co_yield: 값을 호출자에게 반환하고 코루틴의 실행을 일시적으로 중단한다.44 이는 제너레이터(Generator)나 이터레이터(Iterator)를 구현할 때 유용하며, 복잡한 반복 로직을 깔끔하게 표현할 수 있게 한다.55

  • co_return: 코루틴의 실행을 완료하고 최종 결과 값을 반환한다.46 일반

return 문과 달리, 코루틴의 생명주기 관리와 연관되어 동작한다.46

3.3 코루틴이 비동기 프로그래밍에 가져온 변화와 역할

코루틴은 비동기 프로그래밍의 고질적인 문제였던 ’콜백 지옥(Callback Hell)’을 해소하는 데 큰 기여를 한다.4 중첩된 콜백 함수로 인해 코드가 복잡해지고 가독성이 떨어지는 문제를 해결하며, 비동기 코드를 마치 동기 코드처럼 순차적으로 작성할 수 있게 하여 코드 이해 및 유지보수를 용이하게 한다.48

또한, 코루틴은 내부적으로 상태를 저장하고 관리하므로, 개발자가 수동으로 상태 변수를 관리해야 하는 번거로움을 줄여준다.48

co_await를 통해 코루틴 중단/재개가 이루어지며, promise.initial_suspend()promise.final_suspend()와 같은 메커니즘을 통해 코루틴 실행 전후에 사용자 정의 코드를 삽입할 수 있는 무한한 확장성을 제공한다.47

코루틴이 콜백 지옥을 해소하고 동기 코드처럼 비동기 로직을 작성할 수 있게 한다는 점은 개발 생산성과 코드 유지보수성에 직접적인 영향을 미친다. 또한, 스레드 대비 경량성이라는 특성은 대규모 동시성 시스템(예: 수백만 개의 동시 연결을 처리하는 서버)에서 자원 효율성을 극대화하는 핵심 요소가 된다. 이는 단순히 ’편리함’을 넘어 ’확장성’과 ’성능’이라는 근본적인 시스템 요구사항을 충족시키는 전략적 도구임을 시사한다. 코루틴은 C++ 표준 라이브러리의 std::async가 가진 일부 한계(예측 불가능한 실행 정책, future 소멸자의 블로킹)를 보완하며, 더 세밀한 제어와 효율성을 제공한다. 이는 C++이 고성능 시스템 개발에 있어 현대적인 언어들과 경쟁력을 갖추게 하는 중요한 발전으로 평가된다.49

3.4 기존 스레드 기반 방식과의 비교 및 코루틴의 장점

코루틴은 기존 스레드 기반 방식과 비교하여 여러 가지 명확한 장점을 제공한다. 스레드는 운영체제 수준의 스케줄링, 스택 메모리 할당, 컨텍스트 스위칭 비용을 수반하는 ‘무거운’ 개체인 반면 16, 코루틴은 사용자 공간에서 스케줄링되며 훨씬 적은 메모리 오버헤드를 가진 ‘경량’ 개체이다.19 이로 인해 수백만 개의 코루틴을 실행하는 것이 수백 개의 스레드를 실행하는 것보다 훨씬 효율적이다.21

또한, 코루틴은 단일 스레드 내에서 제어권이 변경되는 개념이므로, 멀티 스레드처럼 동시에 실행되지 않아 공유 자원에 대한 동기화 관련 문제가 발생할 가능성이 적고 디버깅이 용이하다.19 특히 네트워크 I/O 작업과 같이 대기 시간이 긴 작업에서 스레드를 블로킹하지 않고 다른 작업을 수행할 수 있도록 하여, 시스템의 처리량과 응답성을 크게 향상시킨다.6

코루틴은 라이브러리 개발자를 위한 저수준 구성 요소로 설계되었으나 52, 그 위에 고수준 추상화를 구축함으로써 일반 개발자도 쉽게 사용할 수 있게 된다.52 이는 C++ 생태계 전반에 걸쳐 비동기 프로그래밍 방식의 변화를 촉진하고, 새로운 비동기 프레임워크 및 라이브러리 개발을 가속화할 잠재력을 가진다.

3.5 표 3: C++20 코루틴 핵심 키워드 및 역할

키워드기능사용 목적
co_await비동기 작업 완료까지 코루틴 실행 일시 중단I/O 작업, 네트워크 요청 등 대기 시간이 긴 작업 처리
co_yield값을 호출자에게 반환하고 코루틴 실행 일시 중단제너레이터(Generator) 또는 이터레이터(Iterator) 구현, 복잡한 반복 로직 표현
co_return코루틴 실행 완료 및 최종 결과 값 반환코루틴의 종료 시점 명시 및 결과 전달

4. 비동기 프로그래밍의 이점

비동기 프로그래밍은 현대 애플리케이션에 여러 가지 중요한 이점을 제공하며, 이는 사용자 경험과 시스템 효율성에 직접적인 영향을 미친다.

4.1 응답성 및 사용자 경험 향상 (UI/UX 반응성 포함)

비동기 방식은 시간이 오래 걸리는 작업을 백그라운드에서 처리함으로써, 메인 스레드가 블로킹되는 것을 방지한다.5 이는 사용자 인터페이스(UI)를 사용하는 애플리케이션에서 특히 중요하며, UI 스레드가 멈추지 않고 사용자 입력에 즉시 반응할 수 있게 한다.5 예를 들어, 쇼핑 앱에서 데이터를 로드하는 동안에도 글꼴 크기 변경과 같은 다른 UI 작업을 동시에 수행할 수 있다.5 결과적으로 사용자에게 더 빠르고 끊김 없는 흐름을 제공하여 전반적인 사용자 경험을 향상시킨다.5

4.2 시스템 자원 활용 효율성 증대

비동기 프로그래밍은 블로킹되는 시간 동안 CPU가 유휴 상태로 있지 않고 다른 작업을 수행할 수 있도록 하여 시스템 자원을 효율적으로 활용한다.8 이는 특히 I/O 바운드 작업(예: 네트워크 요청, 파일 I/O)에서 두드러지며, I/O 작업과 다른 처리 작업을 중첩(overlap)시켜 처리량(throughput)을 개선한다.8 동기 방식이 ‘한 번에 하나씩’ 작업을 처리하며 병목 현상을 유발하는 것과 달리, 비동기 방식은 여러 작업을 동시에 진행하여 CPU 활용도를 높인다.2

비동기 프로그래밍의 이점은 단순히 ’빠르다’는 단일 지표를 넘어선다. ‘응답성’, ‘처리량’, ‘자원 활용 효율성’, ’확장성’이라는 다각적인 성능 지표를 통해 그 가치를 설명할 수 있다.5 이는 현대 시스템에서 요구되는 성능이 단순히 ’작업 완료 시간’뿐 아니라 ’사용자 경험’과 ’시스템 안정성’까지 포괄함을 시사한다. 비동기 프로그래밍이 ’스레드 생성 비용’과 ’컨텍스트 스위칭 오버헤드’를 줄여 자원 효율성을 높인다는 주장은 13, 단순히 스레드 수를 줄이는 것을 넘어, 운영체제 스케줄러의 부담을 줄이고 사용자 공간에서 더 경량의 동시성 단위를 관리하는 코루틴과 같은 메커니즘으로의 발전과 연결된다.

4.3 확장성 및 전반적인 성능 최적화

비동기 방식은 여러 작업을 병렬로 처리할 수 있는 능력을 통해 시스템의 확장성을 높인다.9 이는 대용량 트래픽을 처리하거나 대규모 시스템을 구축할 때 중요한 이점이다.9 동기식 서버가 처리할 수 있는 동시 요청 수보다 비동기식 서버가 훨씬 더 많은 요청을 처리할 수 있으며, 부하 변화에 더 빠르게 반응하여 요청 시간 초과를 줄인다.16 비동기 프로그래밍은 멀티코어 CPU의 효율적인 활용을 가능하게 하여 전반적인 성능 향상을 기대할 수 있다.7

비동기 프로그래밍은 단순히 개발 편의성을 넘어, 비즈니스적 관점에서 ’사용자 만족도’와 ’운영 비용 절감’에 기여하는 핵심 기술이다. 특히 웹 애플리케이션, 게임 엔진, 고성능 서버 등 사용자 상호작용이 중요하거나 대량의 데이터를 처리해야 하는 분야에서 그 중요성이 더욱 부각된다.

5. 비동기 프로그래밍의 도전 과제 및 해결 방안

비동기 프로그래밍은 많은 이점을 제공하지만, 동시에 새로운 복잡성과 잠재적 문제를 야기한다. 이러한 도전 과제를 이해하고 적절한 해결 방안을 모색하는 것이 성공적인 비동기 시스템 구축에 필수적이다.

5.1 복잡성 및 높은 학습 곡선

비동기 프로그래밍은 이벤트 기반 프로그래밍, 콜백, Promise/Future 등 새로운 프로그래밍 모델을 도입하며, 이는 개발자에게 높은 학습 곡선을 요구한다.2 특히 C++에서는 std::async의 기본 실행 정책이 예측 불가능할 수 있고 32,

std::future의 소멸자가 블로킹될 수 있는 등 20 미묘한 동작 방식이 존재하여 이해하기 어렵다. 콜백 기반의 코드는 ’콜백 지옥’을 야기하여 코드 가독성과 유지보수성을 저해한다.4

5.2 경쟁 조건(Race Condition) 및 교착 상태(Deadlock) 발생 가능성

경쟁 조건: 둘 이상의 스레드 또는 프로세스가 공유 자원에 동시에 접근하여 읽기/쓰기 작업을 수행하려 할 때, 실행 순서가 보장되지 않아 결과의 일관성이 무시될 수 있는 상황이다.7 이는 디버깅하기 매우 어렵고, 재현하기 힘든 버그를 유발한다.36

교착 상태: 두 개 이상의 스레드가 서로 상대방이 점유하고 있는 자원을 기다리면서 무한히 대기하는 상태이다.19 이는 시스템의 전체 또는 일부가 멈추는 결과를 초래한다.

5.3 비동기 코드 디버깅의 어려움

비동기 코드는 비선형적이고 시간 의존적인 특성 때문에 디버깅 및 문제 해결이 더 어렵다.2 일반적인 스택 트레이스는 비동기 호출 스택의 전체적인 흐름을 보여주지 못하여 문제의 원인을 파악하기 어렵다.66 로그를 추가하는 것이 오히려 타이밍을 변경하여 경쟁 조건과 같은 버그를 숨길 수 있다는 점도 디버깅을 더욱 복잡하게 만든다.36

5.4 해결 방안: 동기화 기법, 디자인 패턴, 모범 사례

비동기 프로그래밍이 가져오는 성능 및 응답성 이면에는 ’복잡성’이라는 큰 대가가 따른다.2 특히 경쟁 조건과 교착 상태는 미묘하고 재현하기 어려워 디버깅을 극도로 어렵게 만든다.36 이는 단순히 비동기 API를 사용하는 것을 넘어, 동시성 프로그래밍의 깊은 이해와 견고한 설계 원칙, 그리고 체계적인 디버깅 전략이 필수적임을 의미한다.

  • 동기화 기법:

  • std::mutex 및 락 가드: 임계 영역을 보호하여 경쟁 조건을 방지한다. std::lock_guard, std::unique_lock, C++17의 std::scoped_lock은 RAII(Resource Acquisition Is Initialization)를 통해 뮤텍스 잠금/해제를 자동화하고 예외 안전성을 보장하며, std::scoped_lock은 여러 뮤텍스를 안전하게 잠가 교착 상태를 회피하는 데 도움을 준다.17

  • std::condition_variable: 스레드 간의 조건 기반 동기화를 제공하여, 특정 조건이 충족될 때까지 스레드를 효율적으로 대기시키거나 깨울 수 있다.17

  • std::atomic: 간단한 데이터 타입에 대한 락-프리(lock-free) 연산을 제공하여 오버헤드 없이 안전한 동시 접근을 가능하게 한다.17

  • 교착 상태 예방/회피: 자원 할당 순서를 미리 정의하거나 65,

std::lock을 사용하여 여러 뮤텍스를 동시에 안전하게 획득하는 방법 41, 또는 데드락 발생 필수 조건 중 하나 이상을 부정하는 방법(상호 배제 방지, 점유와 대기 방지, 비선점 방지, 순환 대기 방지)을 고려한다.43

  • 디자인 패턴:

  • Producer-Consumer 패턴: 생산자 스레드가 데이터를 생성하고 소비자 스레드가 데이터를 소비하는 방식이다. 공유 큐와 조건 변수를 사용하여 생산자와 소비자 간의 동기화를 효율적으로 관리한다.40 이는 스레드 풀 구현의 핵심 요소이기도 하다.69

  • Proactor 패턴: 비동기 I/O 작업의 완료를 처리하는 데 사용된다. Initiator가 비동기 작업을 시작하면, Asynchronous Operation Processor가 작업을 수행하고, 완료되면 Completion Handler가 호출된다.70 Boost.Asio 라이브러리가 이 패턴을 기반으로 한다.8

  • Callback 패턴: 함수를 다른 함수의 인자로 전달하여 특정 이벤트 발생 시 호출되도록 하는 방식이다.1 이는 비동기 작업의 완료를 알리는 기본적인 메커니즘이나, 중첩될 경우 ’콜백 지옥’을 유발할 수 있다.4

  • Future/Promise 패턴: 비동기 작업의 결과를 미래에 전달하겠다는 ’약속(Promise)’과 그 결과를 받아올 ‘미래(Future)’ 객체를 통해 비동기 데이터 교환 및 동기화 지점을 제공한다.7

  • 모범 사례:

  • std::async 사용 시 std::launch::async 명시: 기본 정책의 예측 불가능성을 피하고 명확한 비동기 실행을 보장한다.32

  • std::future 명시적 대기: 모든 future 객체에 대해 명시적으로 wait() 또는 get()을 호출하여 작업 완료를 보장한다.32

  • 비동기 코드와 동기 코드 혼합 피하기: 비동기 코드가 동기 코드를 블로킹하는 것을 피하고, 비동기 코드는 가능한 한 비동기적으로 호출되도록 ‘Async all the way’ 원칙을 따른다.75

  • 코루틴 예외 처리: try-catch 블록을 사용하여 코루틴 내에서 예외를 적절히 처리하고, CancellationException과 같은 취소 예외는 삼키지 않고 다시 던져 취소 메커니즘이 올바르게 작동하도록 한다.76

  • 스레드 풀 활용: 새로운 스레드를 매번 생성하는 대신 미리 생성된 스레드 풀을 사용하여 스레드 생성/소멸 비용과 오버헤드를 줄인다.13

  • 작업의 세분화 및 모듈화: 복잡한 작업을 작고 독립적인 단위로 분할하여 관리하고 테스트하기 쉽게 만든다.8

  • 시간 여행 디버깅 도구 활용: 경쟁 조건과 같이 재현하기 어려운 비결정적 버그를 진단하는 데 유용하다.36

C++20 코루틴은 ’콜백 지옥’을 해소하고 ’동기 코드처럼 비동기 로직을 작성’하게 하여 복잡성을 완화하는 데 큰 기여를 하지만 48, 여전히 코루틴 프레임워크의 내부 동작에 대한 이해(promise type, awaiter)와 자원 관리(메모리 할당)에 대한 주의가 필요하다.46 이는 코루틴이 만능 해결책이 아니라, 또 다른 수준의 추상화와 이해를 요구하는 도구임을 보여준다. 비동기 프로그래밍의 성공적인 도입은 단순히 기술 팀의 역량뿐 아니라, 코드 리뷰, 테스트, 디버깅 프로세스 등 개발 문화 전반에 걸친 변화를 요구한다. 특히 ’시간 여행 디버깅’과 같은 고급 도구의 필요성은 전통적인 디버깅 방식의 한계를 명확히 보여준다.36

6. 실제 활용 사례

C++ 비동기 프로그래밍은 다양한 분야에서 핵심적인 역할을 수행하며, 애플리케이션의 성능과 사용자 경험을 혁신적으로 개선한다.

6.1 사용자 인터페이스(UI) 개발

UI 애플리케이션은 사용자 입력에 대한 즉각적인 반응성이 필수적이다.5 비동기 프로그래밍은 백그라운드에서 오래 걸리는 작업을 처리하여 UI 스레드가 블로킹되는 것을 막고, 애플리케이션이 항상 응답성을 유지하도록 한다.5 Windows Runtime (WinRT) 앱 모델에서 비동기 프로그래밍은 핵심 구성 요소이며, PPL(Parallel Patterns Library)의 concurrency::task::then과 같은 기능을 통해 비동기 작업을 구성하고 UI 스레드에서 결과를 처리할 수 있다.11 C++20 코루틴은 UI 업데이트나 서버 응답과 같은 비동기 작업을 처리할 때 객체의 상태 전이를 부드럽게 관리하는 데 중요한 역할을 한다.48

6.2 게임 엔진 아키텍처

게임 엔진은 복잡한 로직, 렌더링, 물리 시뮬레이션, 인공지능(AI) 등 다양한 작업을 동시에 처리해야 하므로 멀티스레딩과 비동기 프로그래밍이 필수적이다.13 일반적으로 게임 엔진은 최소한 게임플레이 로직을 위한 스레드와 렌더링을 위한 스레드를 분리하며, 스키닝(skinning)이나 컬링(culling)과 같은 백그라운드 계산을 위한 워커 스레드를 사용한다.13 C++20 코루틴은 캐릭터 행동 시퀀스, 적 AI 패턴, 게임 이벤트 및 컷신 관리, 지연된 효과 및 애니메이션, 레벨 생성 및 로딩과 같이 시간에 따라 진행되는 작업들을 깔끔하게 구현하는 데 매우 유용하다.55 완전 비동기 엔진(예: AsEn)은 코루틴 지원을 통해 확장 가능한 태스크 시스템과 멀티스레드 명령 버퍼 기록 등을 구현한다.79

6.3 네트워크 서버 및 클라이언트 프로그래밍

네트워크 요청(HTTP, 데이터베이스 쿼리 등)은 본질적으로 시간이 오래 걸리는 I/O 바운드 작업이므로, 비동기 처리가 필수적이다.4 비동기 프로그래밍은 서버가 단일 스레드에서 수많은 동시 연결을 효율적으로 처리할 수 있게 하여 처리량과 확장성을 극대화한다.13 gRPC와 같은 프레임워크는 비동기/논블로킹 API를 제공하여 서버와 클라이언트가 CompletionQueue를 통해 RPC 호출을 관리하도록 한다.80 코루틴은 복잡한 비동기 콜백 구조를 제거하고 순차적인 코드 흐름으로 가독성을 높이며, 에러 처리 간소화, 병렬 요청 관리 용이성, 타임아웃 및 취소 처리 간편화 등 네트워크 프로그래밍을 훨씬 간단하게 만든다.55

6.4 고성능 컴퓨팅(HPC) 및 대규모 데이터 처리

대량의 데이터를 병렬로 처리하고 그 결과를 집계하는 작업(예: MapReduce)에서 비동기 프로그래밍은 효율성을 크게 향상시킨다.7 PPL(Parallel Patterns Library) 및 TBB(Threading Building Blocks)와 같은 라이브러리는 고수준의 추상화를 통해 병렬 알고리즘과 데이터 구조를 제공하여 고성능 컴퓨팅을 지원한다.8 비동기 프로그래밍은 로드 밸런싱, 워크로드 분배 알고리즘, GPU 가속과 같은 하드웨어 기능을 활용하여 처리량을 최적화할 수 있게 한다.8

UI, 게임, 네트워크, HPC 등 다양한 도메인에서 비동기 프로그래밍이 ’필수적’으로 언급되는 현상은 6, 비동기성이 특정 영역의 최적화 기법을 넘어 현대 소프트웨어의 핵심 인프라 요소로 자리매김했음을 보여준다. 각 도메인의 특수한 요구사항(UI의 반응성, 게임의 실시간성, 서버의 동시성)이 비동기 프로그래밍을 통해 효과적으로 해결되고 있다. 코루틴이 게임 엔진 55과 네트워크 프로그래밍 55에서 특히 강조되는 이유는, 이들 분야가 I/O 바운드 작업이 많고, 복잡한 상태 관리 및 콜백 지옥 문제에 직면하기 쉬웠기 때문이다. 코루틴은 이 문제들을 ’동기 코드처럼 보이는 비동기 코드’로 해결하여 개발 편의성과 성능을 동시에 잡는 핵심 도구로 부상하였다.

7. 결론 및 제언

C++ 비동기 프로그래밍은 현대 소프트웨어 개발의 핵심 동력이며, 지속적인 발전과 함께 그 중요성이 더욱 커지고 있다.

7.1 C++ 비동기 프로그래밍의 핵심 요약

비동기 프로그래밍은 요청과 결과가 동시에 일어나지 않는 논블로킹 방식으로, CPU 유휴 시간을 최소화하고 시스템 응답성, 자원 효율성, 확장성을 극대화한다. C++ 표준 라이브러리는 std::promise, std::future, std::packaged_task, std::async 등을 통해 비동기 작업을 편리하게 시작하고 결과를 관리하는 고수준 추상화를 제공한다. C++20 코루틴은 co_await, co_yield, co_return 키워드를 도입하여 콜백 지옥을 해소하고 동기 코드처럼 비동기 로직을 작성할 수 있게 함으로써 개발 편의성과 경량성을 혁신적으로 개선하였다. 그러나 경쟁 조건, 교착 상태, 복잡한 디버깅과 같은 도전 과제는 여전히 존재하며, 이를 해결하기 위한 동기화 기법, 디자인 패턴, 모범 사례의 적용이 필수적이다.

7.2 향후 C++ 비동기 프로그래밍의 발전 방향

C++ 표준 위원회는 코루틴을 기반으로 하는 더 강력하고 사용하기 쉬운 비동기 라이브러리(예: Sender/Receiver 모델)를 표준화하는 작업을 진행 중이다. 이는 현재 코루틴의 저수준 특성으로 인해 라이브러리 구현자에게 더 적합하다는 지적을 보완할 것으로 예상된다.52 비동기 스택 트레이스 디버깅 지원과 같은 도구의 발전은 비동기 코드의 디버깅 난이도를 낮추는 데 기여할 것이다.66 Boost.Asio와 같은 외부 라이브러리는 여전히 강력한 비동기 I/O 및 네트워킹 기능을 제공하며, 코루틴과의 통합을 통해 더욱 발전할 것이다.8

7.3 효과적인 비동기 프로그래밍을 위한 권고 사항

C++ 비동기 프로그래밍은 C++11 이후 지속적으로 발전해 왔으며 37, C++20 코루틴의 도입은 그 정점이다. 하지만 여전히 해결해야 할 과제(디버깅 난이도, 라이브러리 지원)가 남아있고, 새로운 표준 기능과 외부 라이브러리가 계속 등장하고 있다. 이는 개발자가 최신 동향을 지속적으로 학습하고, 변화하는 환경에 맞춰 코딩 스타일과 아키텍처를 적응시켜야 함을 의미한다. 비동기 프로그래밍의 복잡성에도 불구하고 그 이점(성능, 응답성, 확장성)이 워낙 크기 때문에, 이는 피할 수 없는 흐름이다. 따라서 ’어떻게 피할까’가 아니라 ’어떻게 잘 활용할까’에 초점을 맞춰야 한다.

  • 개념의 명확한 이해: 동기/비동기, 블로킹/논블로킹, 동시성/병렬성의 차이를 정확히 이해하고 상황에 맞는 패러다임을 선택해야 한다.
  • 적절한 도구 선택: CPU 바운드 작업에는 std::thread를, I/O 바운드 작업이나 복잡한 비동기 흐름에는 C++20 코루틴 또는 std::async를 고려하되, 각 도구의 장단점과 한계를 명확히 인지해야 한다.18
  • 동기화 및 예외 처리 철저: 공유 자원 접근 시 뮤텍스, 조건 변수, 아토믹 연산 등을 사용하여 경쟁 조건과 교착 상태를 예방하고, 비동기 작업에서 발생할 수 있는 예외를 체계적으로 처리해야 한다.17
  • 디자인 패턴 활용: Producer-Consumer, Proactor, Future/Promise 등 검증된 디자인 패턴을 활용하여 복잡한 비동기 로직을 구조화하고 유지보수성을 높인다.8
  • 모범 사례 준수: ‘Async all the way’ 원칙을 따르고, std::async 사용 시 명확한 실행 정책을 지정하며, 스레드 풀과 같은 고급 기법을 고려하여 자원 활용을 최적화해야 한다.13

8. 참고 자료

  1. C++ 동기(synchronous)와 비동기(asynchronous) / 블로킹(blocking)과 논블로킹(non-blocking) - A Game Programmer - 티스토리, https://devshovelinglife.tistory.com/224
  2. Synchronous vs. Asynchronous Programming: How They Differ & When to Use Each, https://distantjob.com/blog/synchronous-vs-asynchronous-programming/
  3. www.mendix.com, https://www.mendix.com/blog/asynchronous-vs-synchronous-programming/#:~:text=Asynchronous%20is%20a%20non%2Dblocking,for%20other%20tasks%20to%20complete.
  4. Exploring Event-Driven and Asynchronous Programming in C++ with NodePP - Medium, https://medium.com/@EDBCBlog/exploring-event-driven-and-asynchronous-programming-in-c-with-nodepp-1678c7462857
  5. Explained: Asynchronous vs. Synchronous Programming - Mendix, https://www.mendix.com/blog/asynchronous-vs-synchronous-programming/
  6. is asynchronus programming essential? : r/learnprogramming - Reddit, https://www.reddit.com/r/learnprogramming/comments/1g1bg71/is_asynchronus_programming_essential/
  7. [Unreal]#비동기 프로그래밍 - 개발 블로그, https://webddevys.tistory.com/523
  8. Asynchronous Programming In C++ For HPC - Code With C, https://www.codewithc.com/asynchronous-programming-in-c-for-hpc/
  9. 비동기 프로그래밍으로 시스템 성능 개선하기 - velog, https://velog.io/@tkjung/%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9C%BC%EB%A1%9C-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EC%84%B1%EB%8A%A5-%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0
  10. Asynchronous Programming in C++ Using PPL - Microsoft Learn, https://learn.microsoft.com/en-us/archive/msdn-magazine/2012/february/asynchronous-programming-asynchronous-programming-in-c-using-ppl
  11. Creating Asynchronous Operations in C++ for UWP Apps - Microsoft Learn, https://learn.microsoft.com/en-us/cpp/parallel/concrt/creating-asynchronous-operations-in-cpp-for-windows-store-apps?view=msvc-170
  12. distantjob.com, https://distantjob.com/blog/synchronous-vs-asynchronous-programming/#:~:text=Pros%20of%20Asynchronous%20Processes%3A,run%20many%20tasks%20at%20once.
  13. How many of you actually use async in your code? : r/cpp_questions - Reddit, https://www.reddit.com/r/cpp_questions/comments/1bhea6y/how_many_of_you_actually_use_async_in_your_code/
  14. Asynchronous Operations - Asio C++ Library, https://think-async.com/Asio/asio-1.30.2/doc/asio/overview/model/async_ops.html
  15. Benchmark of asynchronous code - Software Engineering Stack Exchange, https://softwareengineering.stackexchange.com/questions/208469/benchmark-of-asynchronous-code
  16. Why is async considered better performing than multithreading? - Stack Overflow, https://stackoverflow.com/questions/42857135/why-is-async-considered-better-performing-than-multithreading
  17. Concurrent Programming using C++ Standard Library | by Shafeeq Elanattil | Medium, https://medium.com/@eshafeeqe/concurrent-programming-using-c-standard-library-76e446313083
  18. async thread vs std thread - Stack Overflow, https://stackoverflow.com/questions/78541829/async-thread-vs-std-thread
  19. Thread vs. Coroutine: A Comparative Analysis | by Rameshmoorjani | Medium, https://medium.com/@rameshmoorjani/thread-vs-coroutine-a-comparative-analysis-a1ecc0f0df8d
  20. Async end up creating different thread in c++. Isn’ t it same as multithreading ? : r/cpp_questions - Reddit, https://www.reddit.com/r/cpp_questions/comments/1dkkfnf/async_end_up_creating_different_thread_in_c_isn_t/
  21. Difference between a “coroutine” and a “thread”? - Stack Overflow, https://stackoverflow.com/questions/1934715/difference-between-a-coroutine-and-a-thread
  22. C++ thread와 async의 차이점 - HwanShell - 티스토리, https://hwan-shell.tistory.com/198
  23. [C++] 비동기(Asynchronous) 실행 - 별준 - 티스토리, https://junstar92.tistory.com/190
  24. C++ / std::promise, std::future - Nighthom의 잡동사니 블로그 - 티스토리, https://seungjoon.tistory.com/51
  25. Futures and promises - Wikipedia, https://en.wikipedia.org/wiki/Futures_and_promises
  26. std::promise - future - CPlusPlus.com, https://cplusplus.com/reference/future/promise/
  27. C++ std::async 사용방법. - HwanShell - 티스토리, https://hwan-shell.tistory.com/199
  28. [c++] std::async와 std::thread 사용하기 - JaPa2 - 티스토리, https://ospace.tistory.com/916
  29. [C++ Thread] 약속과 미래 객체, std::promise / std::future - 움직이는 월e - 티스토리, https://narakit.tistory.com/140
  30. [C++] packaged_task - 야곰야곰’s S/W 공부 - 티스토리, https://stormpy.tistory.com/171
  31. [Concurrency] packaged_task - 기존 함수 그대로 thread에 적용(1) - 보리남편 김 주부, https://jabdon4ny.tistory.com/99
  32. What is the issue with std::async? - Stack Overflow, https://stackoverflow.com/questions/12508653/what-is-the-issue-with-stdasync
  33. [Effective Modern C++] 항목 36. 비동기성이 필수일 때에는 std::laynch::async를 지정하라, https://pppgod.tistory.com/57
  34. [C++] std::thread vs std::async - Cyp Software Blog - 티스토리, https://cypsw.tistory.com/entry/C-stdthread-stdasync-%EC%B0%A8%EC%9D%B4%EC%A0%90
  35. [C++] 크리티컬 섹션(CRITICAL SECTION) - study - 티스토리, https://handr95.tistory.com/43
  36. Debugging Race Conditions in C/C++ - Undo.io, https://undo.io/resources/debugging-race-conditions-cpp/
  37. Concurrency in C++ - GeeksforGeeks, https://www.geeksforgeeks.org/cpp/cpp-concurrency/
  38. [C++ Thread] 공유 변수와 경쟁 조건 - 움직이는 월e - 티스토리, https://narakit.tistory.com/135
  39. Secure Coding in C and C++ Race Conditions - Repository [Root Me, https://repository.root-me.org/Programmation/C%20-%20C++/EN%20-%20Secure%20Coding%20in%20C%20and%20C++%20Race%20Conditions.pdf
  40. The Producer Consumer Problem in C++ - Andrew Wei –, https://andrew128.github.io/ProducerConsumer/
  41. Avoiding deadlocks the C++ way, https://vorbrodt.blog/2019/10/12/avoiding-deadlocks-the-c-way/
  42. Producer Consumer problem – C++ Solution using condition variables, https://www.pradeepbangalore.in/post/producer-consumer-problem-c-solution-using-condition-variables
  43. 교착상태(Dead Lock) 해결 방법 - yoongrammer - 티스토리, https://yoongrammer.tistory.com/67
  44. C++20 리서치 - Coroutine[8], https://ence2.github.io/2021/01/c-20-%EB%A6%AC%EC%84%9C%EC%B9%98-coroutine8/
  45. A Comprehensive Discussion on C++20 Coroutines - Alibaba Cloud Community, https://www.alibabacloud.com/blog/a-comprehensive-discussion-on-c%2B%2B20-coroutines_600889
  46. Coroutines (C++20) - cppreference.com, https://en.cppreference.com/w/cpp/language/coroutines.html
  47. Deep Dive into C++20 Coroutines - Medium, https://medium.com/@threehappyer/deep-dive-into-c-20-coroutines-ef5a557d15cb
  48. C++20 Coroutines and Their Role in Asynchronous Objects - SimplifyC++, https://www.simplifycpp.org/index.php?id=a0198
  49. What Did C++20 Coroutines Add to the Power of C++ and Multithreading - SimplifyC++, https://www.simplifycpp.org/index.php?id=a0186
  50. C++ 20 : Corutine(중요) - 응애프로그래머의 공부일지 - 티스토리, https://bio200127.tistory.com/165
  51. What are some of the use case for coroutines? : r/cpp - Reddit, https://www.reddit.com/r/cpp/comments/y9q539/what_are_some_of_the_use_case_for_coroutines/
  52. Part of this is that I’m tired, but it blows my mind how difficult C++ coroutine… | Hacker News, https://news.ycombinator.com/item?id=26222342
  53. Harnessing the Power of Async in C++20: What’s New and What’s Next | by Byte Blog, https://byteblog.medium.com/harnessing-the-power-of-async-in-c-20-whats-new-and-what-s-next-039adc64c348
  54. Writing custom C++20 coroutine systems, https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/coroutines-c++20/
  55. C++ 20 코루틴 실전 활용 가이드: 비동기 프로그래밍의 혁명 - 재능넷, https://www.jaenung.net/tree/23647
  56. C++20 Coroutines: sketching a minimal async framework - Jeremy’s Blog, https://www.jeremyong.com/cpp/2021/01/04/cpp20-coroutines-a-minimal-async-framework/
  57. C++20) Coroutine ( 코루틴 ) - 3 - 나만의 연습장 - 티스토리, https://openmynotepad.tistory.com/67
  58. C++20) Coroutine ( 코루틴 ) - 3 - 나만의 연습장 - 티스토리, https://openmynotepad.tistory.com/m/67
  59. C++ Coroutines Part 1: co_yield, co_return and a Prime Sieve | Nigel Tao, https://nigeltao.github.io/blog/2023/cpp-coro-part-1-yield-return-prime-sieve.html
  60. 제네릭 프로그래밍과 디자인 패턴을 적용한 Modern C++ Design(번역서) 정리, http://ajwmain.iptime.org/programming/book_summary/%5B04%5Dmodern_cpp_design/modern_cpp_design.html
  61. c++20 Coroutine 활용 - Umundu’s Zapary, https://zapary.blogspot.com/2021/12/cpp20-coroutine-usage.html
  62. C++ run a function in async and not block the ui - Stack Overflow, https://stackoverflow.com/questions/30161184/c-run-a-function-in-async-and-not-block-the-ui
  63. 비동기 프로그래밍의 이해와 실제 적용 사례 - F-Lab, https://f-lab.kr/insight/understanding-and-applying-asynchronous-programming
  64. asynchronous-design-patterns, https://vivmagarwal.github.io/js-design-patterns/pages/asynchronous-design-patterns/index.html
  65. CON53-CPP. Avoid deadlock by locking in a predefined order - Confluence, https://wiki.sei.cmu.edu/confluence/display/cplusplus/CON53-CPP.+Avoid+deadlock+by+locking+in+a+predefined+order
  66. Async Stacks: Making Senders and Coroutines Debuggable - Ian Petersen & Jessica Wong - CppCon 2024 - YouTube, https://www.youtube.com/watch?v=nHy2cA9ZDbw
  67. Debug an async application - Visual Studio (Windows) | Microsoft Learn, https://learn.microsoft.com/en-us/visualstudio/debugger/walkthrough-debugging-a-parallel-application?view=vs-2022
  68. [OS] 교착상태 해결 방법 예방, 회피, 탐지 - Hoyeon, https://hoyeonkim795.github.io/posts/%EA%B5%90%EC%B0%A9%EC%83%81%ED%83%9C%ED%95%B4%EA%B2%B0%EB%B0%A9%EB%B2%95/
  69. [C++] C++20 동시성 컨테이너를 사용하여 ThreadPool 설계하기 - 움직이는 월e, https://narakit.tistory.com/234
  70. Boost.Asio 개요 - 핵심 개념 및 기능 - Proactor 디자인 패턴: 스레드 없는 동시 실행 - 까마귀75, https://devdockr.tistory.com/9
  71. endurodave/AsyncCallback: C++ Asynchronous Multicast Callbacks - GitHub, https://github.com/endurodave/AsyncCallback
  72. C++11 async parallel callback (Example) - Coderwall, https://coderwall.com/p/f-vypa/c-11-async-parallel-callback
  73. C-C++ Code Example: Reading Messages Asynchronously Using a Callback Function, https://learn.microsoft.com/en-us/previous-versions/windows/desktop/msmq/ms699828(v=vs.85)
  74. Callback (computer programming) - Wikipedia, https://en.wikipedia.org/wiki/Callback_(computer_programming)
  75. Async/Await - Best Practices in Asynchronous Programming | Microsoft Learn, https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
  76. Coroutine: Best Practices. Elevate Your Asynchronous Programming… | by Vivek Bansal | Medium, https://medium.com/@vivekbansal19/coroutine-best-practices-affddb50ae1b
  77. Building a Thread Pool with C++ and STL - Coding Notes, https://nixiz.github.io/yazilim-notlari/2023/10/07/thread_pool-en
  78. Thread Pool In C++ - YouTube, https://www.youtube.com/watch?v=u7ouCuieBhI
  79. azhirnov/as-en: async game engine - GitHub, https://github.com/azhirnov/as-en
  80. Asynchronous-API tutorial | C++ - gRPC, https://grpc.io/docs/languages/cpp/async/