46. 완료 슬롯의 비휘발성 플래그: 무한 스핀과 결과 가시성 결여
난이도 상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] 커스텀 완료 슬롯(경량 future)의 결과·완료 플래그 게시
// ----------------------------------------------------------------------------
// 시나리오:
// 비동기 DB/RPC 응답을 기다리기 위해 경량 완료 슬롯을 직접 만들었다.
// - 생산자 스레드(응답 처리기)가 결과를 채우고 "완료" 로 표시한다.
// - 소비자 스레드(요청한 게임 로직)가 완료될 때까지 기다렸다가 결과를 읽는다.
// 태스크/이벤트 대신 가볍게 돌리려고 플래그와 필드만 사용했다.
//
// 요구사항:
// - 소비자는 완료 후 결과를 정확히 읽어야 한다(기본값/쓰레기값을 읽으면 안 된다).
// - 소비자가 완료를 영원히 못 보고 멈추는 일이 없어야 한다.
//
// 과제:
// CompletionSlot<T> 의 Complete (A) 와 Wait (B) 를 검토하라. 생산자와 소비자가
// 서로 다른 스레드일 때 어떤 결과가 나올 수 있는지, 어떻게 고쳐야 하는지 설명하라.
// ============================================================================
public sealed class CompletionSlot<T>
{
private T _result = default!;
private bool _done;
public void Complete(T value)
{
_result = value;
_done = true; // (A)
}
public T Wait()
{
while (!_done) { } // (B)
return _result;
}
public bool TryGet(out T value)
{
if (_done) { value = _result; return true; }
value = default!;
return false;
}
} 결함 코드 · C++
// ============================================================================
// [코드리뷰 문제] 커스텀 완료 슬롯(경량 future)의 결과 게시
// ----------------------------------------------------------------------------
// 시나리오:
// 비동기 DB/RPC 응답을 기다리기 위해 경량 완료 슬롯을 직접 만들었다.
// - 생산자 스레드가 결과를 채우고 완료 플래그를 세운다.
// - 소비자 스레드가 완료될 때까지 기다렸다가 결과를 읽는다.
// 플래그는 atomic<bool> 로 두었다.
//
// 요구사항:
// - 소비자는 완료 후 결과를 정확히 읽어야 한다(초기화 전/쓰레기값 금지).
// - 완료를 못 보고 멈추는 일이 없어야 한다.
//
// 과제:
// CompletionSlot<T> 의 complete (A) 와 wait (B) 를 검토하라.
// 생산자·소비자가 서로 다른 스레드일 때 어떤 결과가 나올 수 있는지, 어떻게 고쳐야 하는지 설명하라.
// ============================================================================
#include <atomic>
template <class T>
class CompletionSlot {
public:
void complete(const T& value) {
result_ = value;
done_.store(true, std::memory_order_relaxed); // (A)
}
T wait() {
while (!done_.load(std::memory_order_relaxed)) { // (B)
// busy wait
}
return result_;
}
bool tryGet(T& out) {
if (done_.load(std::memory_order_relaxed)) { out = result_; return true; }
return false;
}
private:
T result_{};
std::atomic<bool> done_{false};
};
// 사용 예시(설명용): 서로 다른 스레드에서 complete / wait 호출
struct RpcResult { long value; long checksum; };
CompletionSlot<RpcResult> g_slot; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.