C++ 코루틴이 비동기 I/O를 기다리는 동안 호출자가 종료됩니다. 나중에 코루틴이 재개될 때 참조하던 객체와 버퍼가 유효하도록 수명을 어떻게 관리하나요?
잠깐, 답변을 보기 전에
먼저 내 말로 설명해 볼까요?
답변과 점검 포인트 펼치기답변 접기
구두 답변
정의를 외우기보다, 원리와 조건을 연결해 설명해 보세요.
코루틴은 함수가 중단돼도 나중에 이어서 실행할 상태를 프레임에 유지합니다. 하지만 프레임에 참조가 들어 있다고 참조 대상의 수명까지 늘어나지는 않습니다. 호출자가 넘긴 객체가 먼저 파괴되면 재개 시 잘못된 메모리를 사용할 수 있습니다.
프레임에 남는 것과 빌린 것
예를 들어 지역 버퍼를 참조하는 비동기 쓰기를 시작하고 호출자가 반환한다고 하겠습니다. 쓰기가 끝나기 전에 버퍼가 없어지면 위험합니다. 저는 비동기 작업이 버퍼를 소유하게 하거나, 완료가 확인될 때까지 소유 객체를 유지하도록 계약을 정하겠습니다. 멤버 코루틴이 this를 참조하는 경우에도 객체가 코루틴보다 오래 사는지 따로 확인해야 합니다. 캡처가 있는 코루틴 람다도 클로저와 프레임 수명을 혼동하기 쉽습니다.
취소·완료·파괴의 선형화
취소 때는 더 조심해야 합니다. 기다리기를 포기했다고 실행 중 I/O가 프레임을 더 이상 참조하지 않는 것은 아닙니다. 완료 콜백이 다시 resume할 수 있는 상태에서 프레임을 파괴하면 오류가 납니다. 취소와 완료 중 누가 최종 정리를 하는지 한 상태 전이로 관리하고, 다시 재개되지 않는다는 보장이 생긴 뒤 파괴하겠습니다. 테스트에서는 즉시 완료, 늦은 완료, 취소 직후 완료를 각각 재현하겠습니다. 코루틴 문법이 콜백 코드를 짧게 해 주지만 수명 계약을 없애 주는 것은 아닙니다.
선택 기준과 검증
반례는 프레임에 std::span만 저장한 경우입니다. 포인터와 길이는 남지만 원래 지역 배열의 소유권은 남지 않으므로, 호출자가 반환한 뒤 재개하면 dangling reference가 됩니다. 버퍼를 프레임으로 이동하면 이 문제는 줄지만 메모리를 완료까지 보유하고 이동 비용을 치릅니다. 반환 객체가 복사·이동될 때 코루틴 핸들의 단독 소유가 유지되는지도 확인하겠습니다.
중단 지점에서는 프레임에 보관되는 값 매개변수와 빌린 참조를 구분하겠습니다. 멤버 함수의 this는 객체를 소유하는 스마트 포인터가 아니므로 객체가 별도로 살아 있어야 합니다. 캡처 람다는 람다 클로저와 코루틴 프레임이 다른 객체일 수 있어, 임시 람다를 호출한 뒤 중단되는 코드에서 캡처 수명을 특히 확인해야 합니다. 작업의 상태를 오래 살려 두는 것과 I/O 버퍼를 오래 살려 두는 것은 각각 필요할 수 있습니다.
await_suspend에서 작업을 등록하자마자 다른 스레드가 완료를 전달할 수도 있습니다. 그러므로 등록 이후 awaiter나 프레임이 계속 유효하다고 가정하고 필드를 덧쓰지 않도록 라이브러리의 재진입 계약을 확인하겠습니다. 완료와 파괴는 동시에 수행하지 않고, 외부 완료 등록이 제거됐거나 drain된 뒤에만 파괴합니다. 세대 번호는 잘못된 결과 적용을 거절할 수 있지만 해제된 포인터 접근 자체를 안전하게 만들지는 않습니다.
검증에서는 반환 객체를 이동한 뒤 원래 객체가 파괴되는 경우, 첫 중단 이전에 예외가 나는 경우, final_suspend에서 멈춘 채 결과 소비자가 사라지는 경우를 나눠 확인하겠습니다. C++20 코루틴은 실행 위치나 취소 정책을 언어 자체로 고정하지 않으므로 반환 타입과 awaiter 구현의 계약이 함께 필요합니다.
득점 포인트
이해가 드러나는 지점을 확인해 보세요.
- 코루틴 프레임과 참조 대상의 수명을 별도 계약으로 분석한다.
- 취소·완료 경합에서 resume·파괴의 단일 책임을 정한다.
- 언어 규칙과 비동기 I/O 라이브러리의 버퍼 계약을 구분한다.
감점 포인트
놓치기 쉬운 조건과 오해를 짚어 보세요.
- 코루틴 프레임이 참조 대상의 수명까지 자동 연장한다고 말한다.
- 취소 직후 핸들을 파괴해 늦은 완료가 접근하는 경로를 놓친다.
- shared_ptr 하나로 resume 중복과 상태 경합까지 해결된다고 단정한다.
더 파고들 거리
하나 더 질문하며 이해의 범위를 넓혀 보세요.
- C++ 코루틴이 final_suspend에 도달했습니다. 핸들과 프레임을 누가 언제 destroy해야 하나요?
- 완료 통지와 취소 통지가 같은 틱에 오면 어느 상태 전이를 승자로 기록할까요?
- C++ 코루틴 프레임을 다른 스레드에서 파괴할 수 있습니다. 스레드에 종속된 자원의 소멸 위치는 어떻게 보장하나요?
득점·감점 포인트는 학습용 자기 점검 기준이며, 특정 회사의 실제 채점표가 아닙니다.
원리부터 공부하고 싶다면
답변을 보충하는 개념·예제·슈도코드를 읽어 보세요.