50. 조회 경로에서의 비원자 삽입(무락 Dictionary 동시 변형)
난이도 상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// 시나리오: 온라인 플레이어 통계 조회 레지스트리 — C# 서버
// - 여러 워커 스레드가 _stats(Dictionary<int, PlayerStat>) 를 동시에 조회한다.
// 워크로드는 압도적으로 "조회(읽기)" 위주다.
// - 조회 시 항목이 아직 없으면 기본 PlayerStat 를 만들어 넣고 반환하는 편의 헬퍼를 쓴다.
//
// 요구사항:
// 1) 여러 스레드가 동시에 조회해도 자료구조가 안전해야 한다.
// 2) 조회가 의도치 않은 부작용이나 스레드 간 경합을 만들면 안 된다.
//
// 과제: 여러 스레드가 동시에 GetOrCreate 를 호출하면 예외가 나거나 통계가
// 유실/중복 생성된다. (A),(B) 지점을 근거로 원인과 수정안을 설명하라.
using System;
using System.Collections.Generic;
public sealed class PlayerStat { public int Kills; }
public sealed class StatsRegistry
{
private readonly Dictionary<int, PlayerStat> _stats = new Dictionary<int, PlayerStat>();
public PlayerStat GetOrCreate(int playerId)
{
if (!_stats.TryGetValue(playerId, out var s)) // (A)
{
s = new PlayerStat();
_stats[playerId] = s; // (B)
}
return s;
}
public void AddKill(int playerId)
{
var s = GetOrCreate(playerId);
s.Kills++;
}
} 결함 코드 · C++
// 시나리오: 온라인 플레이어 통계 조회 레지스트리 — C++ 서버
// - 여러 워커 스레드가 stats_(unordered_map<int, PlayerStat>) 를 동시에 조회한다.
// 워크로드는 압도적으로 "조회(읽기)" 위주다.
// - 조회는 아래 헬퍼로 이뤄진다.
//
// 요구사항:
// 1) 여러 스레드가 동시에 조회해도 자료구조가 안전해야 한다.
// 2) 조회가 의도치 않은 부작용이나 경합을 만들면 안 된다.
//
// 과제: 여러 스레드가 동시에 GetOrCreate 를 호출하면 자료구조가 깨지거나 통계가
// 유실된다. (A),(B) 지점을 근거로 원인과 수정안을 설명하라. (컴파일 가능해야 함)
#include <cstdio>
#include <unordered_map>
struct PlayerStat { int kills = 0; };
class StatsRegistry {
public:
PlayerStat& GetOrCreate(int player_id) {
return stats_[player_id]; // (A) (B)
}
void AddKill(int player_id) {
PlayerStat& s = GetOrCreate(player_id);
s.kills++;
}
size_t Size() const { return stats_.size(); }
private:
std::unordered_map<int, PlayerStat> stats_;
};
int main() {
StatsRegistry reg;
reg.AddKill(1);
reg.AddKill(1);
std::printf("kills=%d size=%zu\n", reg.GetOrCreate(1).kills, reg.Size());
return 0;
} 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.