14. 던전 인스턴스 정원 초과 (동시 입장 경합) — C#

난이도 중 해설 보기 →

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

결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - 던전 인스턴스 정원 초과 (동시 입장 경합)
// ----------------------------------------------------------------------------
// 시나리오 (동시성/메모리):
//   - 파티/매칭이 잡히면 던전 인스턴스가 생성되고, 정원(capacity, 예: 5)만큼
//     플레이어가 거의 동시에 C_EnterInstance 를 보낸다.
//   - 여러 IO/로직 스레드가 같은 인스턴스의 TryEnter 를 동시에 호출한다.
//   - 인스턴스에는 정원 초과로 입장시키면 안 된다(6번째는 거부).
//   - 같은 플레이어가 더블클릭/재전송으로 두 번 입장 요청할 수도 있다(중복 입장 금지).
//
// 요구사항:
//   - 어떤 동시 입장 폭주에서도 members 수는 capacity 를 넘지 않아야 한다.
//   - 같은 플레이어는 한 번만 멤버가 되어야 한다.
//   - 입장 카운트와 멤버 목록은 항상 일관돼야 한다(부분 반영 금지).
//
// 과제:
//   이 코드의 잠재적 문제를 모두 찾고, 왜/어떻게 깨지는지(경합 인터리빙 포함)
//   설명하고, 수정안과 더 나은 설계를 제시하라.
//   (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

using System.Collections.Generic;
using System.Linq;
using System.Threading;

public class DungeonInstance
{
    private readonly int       _capacity;
    private int                _count = 0;
    private readonly List<long> _members = new List<long>();

    public DungeonInstance(int capacity) { _capacity = capacity; }

    // C_EnterInstance 처리. 입장 성공 시 true.
    public bool TryEnter(long playerId)
    {
        // (A) 정원 검사
        if (Volatile.Read(ref _count) >= _capacity)
            return false;

        // (B) 중복 입장 검사
        if (_members.Contains(playerId))
            return false;

        // (C) 입장 반영
        _members.Add(playerId);
        Interlocked.Increment(ref _count);

        return true;
    }

    public int Count => Volatile.Read(ref _count);
}
내 리뷰 · C#
내 답안 · 자동 저장

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