39. 낙관적 스냅샷(seqlock)의 잘못된 구현: 찢긴 읽기 (C#)

난이도 최상 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// 시나리오: 게임 서버 — 자주 읽히고 가끔 쓰이는 플레이어 트랜스폼 스냅샷
//
// 한 플레이어의 위치/속도(트랜스폼)는 물리 스레드 1개가 갱신하고, 다수의
// 스레드(AOI 브로드캐스트, 충돌 판정, 스킬 판정)가 매우 빈번히 읽는다.
// 읽기가 압도적으로 많아 뮤텍스 대신 "버전 카운터 기반 낙관적 읽기"로 설계했다.
//
// 요구사항:
//  - 읽는 쪽은 항상 "한 시점의 일관된 스냅샷"(같은 갱신에서 나온 x,y,z,vx,vy)을
//    얻어야 한다. 서로 다른 갱신의 필드가 섞인 값은 허용되지 않는다.
//  - 쓰기는 1개 스레드, 읽기는 다수.
//
// 아래 낙관적 스냅샷 구현을 검토하라.

using System.Threading;

public sealed class TransformSnapshot
{
    private int _version;
    private float _x, _y, _z, _vx, _vy;

    // 물리 스레드(단일 writer): 새 트랜스폼을 게시
    public void Write(float x, float y, float z, float vx, float vy)
    {
        _x = x; _y = y; _z = z;              // (A) 필드 갱신
        _vx = vx; _vy = vy;
        _version++;                          // (B) 갱신 완료 표시
    }

    // 다수 reader: 일관된 스냅샷을 읽는다
    public (float x, float y, float z, float vx, float vy) Read()
    {
        int v = _version;                    // (C) 버전 스냅샷
        float x = _x, y = _y, z = _z, vx = _vx, vy = _vy;
        // v 를 읽었으니 이 스냅샷은 버전 v 의 것이라고 간주한다.
        return (x, y, z, vx, vy);
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.