37. 필드 자원 노드 동시 채집: 검사-차감 비원자와 고갈 디스폰 경합 (C#)

난이도 중 해설 보기 →

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

결함 코드 · C#
// [시나리오] MMORPG 필드 자원 채집 (서버-클라)
// 광맥/약초 같은 필드 자원 노드는 "채집 가능 횟수(Remaining)"를 가진다.
// 여러 플레이어가 같은 노드를 동시에 채집 시도할 수 있고, 각 채집 요청은
// 네트워크 수신 스레드풀의 서로 다른 워커에서 병렬로 처리된다.
// 채집이 성공하면 플레이어 인벤토리에 자원 아이템을 지급하고 Remaining 을 줄이며,
// Remaining 이 소진되면 노드를 월드에서 제거(디스폰)한다.
//
// [요구사항]
//   - 한 노드에서 실제로 지급되는 자원 총량은 그 노드의 초기 Remaining 을 넘지 않아야 한다.
//   - 고갈된 노드는 정확히 한 번만 디스폰되어야 한다.
//
// [과제] HarvestHandler.OnHarvest 를 검토하고, 다수 워커가 같은 노드를 동시
//        채집할 때 위 요구사항이 어떻게 어긋날 수 있는지 원인과 수정안을 제시하라.
//        표시된 (A)(B) 지점에 주목하라.

using System;
using System.Collections.Generic;

class ResourceNode
{
    public int NodeId;
    public string ItemId;
    public int Remaining;    // 남은 채집 횟수
    public bool Despawned;
}

class HarvestHandler
{
    // nodeId -> 필드에 스폰된 자원 노드
    private readonly Dictionary<int, ResourceNode> _nodes = new();

    private void GrantItem(int playerId, string itemId, int qty) { /* 인벤토리 지급 */ }
    private void DespawnNode(ResourceNode node)
    {
        _nodes.Remove(node.NodeId);   // 월드에서 제거
        node.Despawned = true;        // 클라 통지
    }

    // 여러 워커 스레드에서 동시에 호출된다.
    public bool OnHarvest(int playerId, int nodeId)
    {
        if (!_nodes.TryGetValue(nodeId, out ResourceNode node) || node.Despawned)
            return false;

        // (A)
        if (node.Remaining <= 0)
            return false;

        GrantItem(playerId, node.ItemId, 1);
        node.Remaining -= 1;

        // (B)
        if (node.Remaining == 0)
            DespawnNode(node);

        return true;
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

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