ONE QUESTION AT A TIME.

천천히 생각하고, 분명하게.

TODAY’S QUESTION714 / 1500
네트워크난이도 중하5분 답변 목표 · 보강본

연결 종료를 위해 CancelIoEx를 호출했고 성공했습니다. 해당 OVERLAPPED와 수신 버퍼를 바로 풀에 반환해도 되나요?

잠깐, 답변을 보기 전에
먼저 내 말로 설명해 볼까요?

답변과 점검 포인트 펼치기답변 접기
01

구두 답변

정의를 외우기보다, 원리와 조건을 연결해 설명해 보세요.

안 됩니다. CancelIoEx가 취소 요청을 받아들였거나 대상 I/O를 찾지 못했다는 결과는 OVERLAPPED와 버퍼에 대한 모든 커널 접근과 완료 처리가 끝났다는 뜻이 아닙니다. 취소와 정상 완료가 경합하면 정상 바이트 수로 완료될 수도 있고 취소 오류로 완료될 수도 있으므로, 완료 포트를 계속 소비하고 해당 작업이 종결된 뒤에만 메모리를 풀에 돌려보내야 합니다.

취소와 작업 수명

중첩 소켓 I/O에서는 OVERLAPPED가 작업 상태를 담고 버퍼 주소가 커널에 전달됩니다. CancelIoEx(handle, &ov)는 특정 작업의 취소를 요청하는 동작이지 동기적인 free 명령이 아닙니다. 호출 직전 I/O가 이미 완료 큐에 게시됐거나 커널이 완료를 진행 중일 수 있습니다. 연결 종료 상태에 들어갈 때 먼저 새 제출을 막고, 작업별 미완료 카운터를 제출 전에 예약합니다. 제출 자체가 즉시 실패하면 그 예약을 되돌리고, 성공 또는 ERROR_IO_PENDING이면 완료·취소·오류 중 한 번의 완료 경로에서 카운터를 줄입니다. 이를 취소 후 drain(cancellation drain)이라고 부릅니다.

연결 컨텍스트는 논리적으로 닫힌 뒤에도 미완료 작업의 참조를 유지합니다. 정상 완료·취소·기타 오류를 하나의 종결 경로에서 처리하고, 마지막 작업이 완료되고 연결 참조가 0이 된 시점에 소켓·버퍼·작업 객체를 반환합니다. 논리적으로 적용하지 않는 것과 물리적으로 메모리를 해제하는 것은 다릅니다. 세대 번호나 작업 ID는 늦은 완료를 논리적으로 무효화하는 데 도움을 주지만, 이미 해제된 포인터를 안전하게 되살리지 못합니다. 따라서 실제 drain 전에는 메모리를 절대 재사용하지 않겠습니다.

오류와 검증

CancelIoEx가 ERROR_NOT_FOUND를 돌려줘도 애플리케이션이 추적한 제출 상태와 완료 여부를 기준으로 판단합니다. 이미 완료 큐에 들어갔거나 완료 직전일 수 있으므로 조기 free의 근거로 쓰지 않습니다. 작업 카운터는 제출 전 예약·즉시 실패 롤백·완료 시 1회 감소라는 불변식을 갖게 합니다. 종료 deadline을 넘겨도 버퍼를 강제 free하지 않으며, 강제 종료가 필요하면 미완료 I/O 수명 보장을 포기하는 범위를 프로세스 격리로 한정합니다.

테스트는 취소 직전 정상 완료, 취소 직후 완료, 취소 오류, 반복 취소, 소켓 종료와 풀 주소 재사용을 경합시킵니다. 논리 폐기된 결과가 상위 상태에 적용되지 않으면서도 작업 컨텍스트가 마지막 완료까지 유지되는지, 제출·롤백·완료 카운터가 한 번씩만 변하는지를 확인하겠습니다.

추가 조건과 판단

종료와 제출 사이의 경쟁도 막아야 합니다. 제출 스레드가 종료 플래그를 확인한 직후 멈추고, 종료 스레드가 작업 수 0을 확인해 자원을 해제한 뒤 제출이 재개되면 취소 로직이 올바르더라도 위험합니다. 제출 허가와 미완료 예약을 같은 상태 전이로 보호해 종료가 시작된 뒤 새로운 제출이 승인되지 않도록 하겠습니다. 이는 단순한 atomic 카운터 하나보다 넓은 불변식입니다.

완료 워커가 카운터를 줄이는 시점도 전체 정리의 끝이어야 합니다. 패킷을 꺼낸 즉시 0으로 만들고 나중에 버퍼를 파싱한다면 종료 스레드가 그 사이 연결을 해제할 수 있습니다. 커널 I/O 종료와 사용자 후속 처리 종료를 별도 참조로 추적하거나, 후속 처리까지 끝난 뒤 마지막 참조를 내려놓겠습니다. 취소된 요청의 데이터는 적용하지 않아도 그 참조 반환은 생략하지 않습니다. 이런 소유 모델을 제출 시각·취소 시각·완료 시각과 작업 ID로 기록하면 카운터 누수와 이중 반환을 구분할 수 있습니다.

02

득점 포인트

이해가 드러나는 지점을 확인해 보세요.

  • CancelIoEx의 취소 요청과 실제 I/O 완료·메모리 접근 종료를 분리한다.
  • 제출 차단·완료 drain·마지막 참조 해제의 순서를 제시한다.
  • 정상 완료와 취소 오류가 경합할 수 있고 ERROR_NOT_FOUND를 조기 free 근거로 삼지 않는다.
  • 논리적 무효화와 물리적 버퍼 재사용을 구분한다.
03

감점 포인트

놓치기 쉬운 조건과 오해를 짚어 보세요.

  • CancelIoEx 성공이면 OVERLAPPED와 버퍼를 즉시 풀에 반환한다.
  • 소켓 close나 취소 실패가 이미 모든 완료 콜백을 없앴다고 단정한다.
  • 논리적으로 버린 완료를 메모리 정리까지 생략하는 것으로 처리한다.
04

더 파고들 거리

하나 더 질문하며 이해의 범위를 넓혀 보세요.

득점·감점 포인트는 학습용 자기 점검 기준이며, 특정 회사의 실제 채점표가 아닙니다.

원리부터 공부하고 싶다면

답변을 보충하는 개념·예제·슈도코드를 읽어 보세요.

← 전체 질문 보기