[말랑 퀴즈] 26/10/11 해답
카테고리: MallangQuiz
태그: Quiz
제 말랑말랑 퀴즈 생성기는 이곳에서 확인하실 수 있습니다.
말랑말랑 퀴즈 — 해답지 ✅
날짜: 2026-10-11 문제 수: 6문제 총점: 55.8/60 (93점) 🏆 훌륭해요
📊 채점 결과
| 문항 | 유형 | 난이도 | 결과 | 점수 |
|---|---|---|---|---|
| Q1 | OX | 🟢 쉬움 | 🔺 부분 정답 | 9 / 10 |
| Q2 | 객관식 | 🟡 보통 | ⭕ 정답 | 10 / 10 |
| Q3 | 빈칸 채우기 | 🟡 보통 | ⭕ 정답 | 10 / 10 |
| Q4 | OX | 🟢 쉬움 | ⭕ 정답 | 10 / 10 |
| Q5 | 서술형 | 🔴 어려움 | 🔺 부분 정답 | 8.5 / 10 |
| Q6 📌 | 서술형 | 🟡 보통 | 🔺 부분 정답 | 8.3 / 10 |
| 합계 | 55.8 / 60 |
총평
객관식·빈칸·OX 문제를 거의 다 맞혔고, 어려운 C++ traits 문제(Q5)도 (1), (2), (4)는 정확하게 답했습니다. 아쉬운 부분은 개념의 “이름”과 “근거 표현”입니다. Q5(3)은 컴파일 도중/런타임의 구분이 빠졌고, Q6(3)은 DB의 락을 임계 영역에 대응시키지 못하고 레이스 컨디션을 답했습니다. Q1의 근거에서는 데이터 영역이 프로그램에 이미 있다는 점을 놓쳤습니다.
Q1. 🟢 쉬움 — 🔺 9/10
문제: 다음 명제가 참(O)인지 거짓(X)인지 판단하라.
프로그램은 실행 전 상태의 파일로 코드와 데이터, 힙, 스택 영역을 모두 갖추고 있으며, 프로세스로 실행될 때 이 네 영역이 그대로 메모리에 적재된다.
📝 내 답: X. 데이터, 힙, 스택 영역은 프로세스로 실행되고 난 뒤 적재된다.
정답: X
해설:
프로그램은 실행 전 상태의 파일로 코드와 데이터로 구성됩니다. 프로세스가 되어 메모리에 적재될 때 코드와 데이터는 프로그램에서 가져오고, 힙(동적 메모리)과 스택(함수 호출 기록 및 로컬 변수)이 추가됩니다. 따라서 프로그램이 처음부터 힙과 스택을 갖추고 있다는 설명이 틀렸습니다.
🔍 피드백: 판단(X)은 맞아서 7점입니다. 근거는 “힙과 스택이 실행 후에 생긴다”는 핵심은 맞지만, 데이터 영역까지 실행 후에 적재된다고 쓴 것은 틀렸습니다. 데이터는 프로그램 파일에 이미 들어 있고, 실행 후에 추가되는 것은 힙과 스택뿐입니다. 근거 3점 중 2점을 드렸습니다.
출처:
server/game_server/1/2025-04-25-game_server_1_1.md
Q2. 🟡 보통 — ⭕ 10/10
문제: 멀티스레드 게임 서버에서 잠금 범위를 “방 단위”로 설정한 아래 구조에 대한 설명으로 가장 올바른 것은?
class MyGameServer {
class Room {
CriticalSection m_critSec; // 방 뮤텍스
String m_roomName;
List<Player> m_players;
List<Character> m_characters;
}
map<PlayerID, shared_ptr<Room>> m_roomList;
String m_serverName;
CriticalSection m_critSec; // 서버 뮤텍스
}
MyGameServer.DoSomething(playerID) {
lock(m_critSec); // 1
room = m_roomList.find(player); // 2
unlock(m_critSec); // 3
lock(room.m_critSec); // 4
room.DoSomething(playerID); // 5
unlock(room.m_critSec); // 6
}
- A. 서버 뮤텍스는 서버 메인과 방 목록뿐 아니라 방 안의 데이터까지 함께 보호한다.
- B. 플레이어가 있는 방을 방 목록에서 찾을 때는 서버 뮤텍스를, 그 방 안에서 처리할 일을 할 때는 해당 방의 뮤텍스를 잠근다.
- C. 잠금 범위는 서버 전체에 뮤텍스 하나만 두는 것이 가장 적당하다.
- D. 파일을 액세스할 때는 자주 잠그는 뮤텍스를 잠근 채로 하는 편이 성능 저하를 줄여 준다.
📝 내 선택: B
정답: B
해설:
서버 뮤텍스는 서버 메인과 방 목록을 보호하고, 방 안의 데이터는 각 방의 뮤텍스가 보호합니다. 코드의 1~3번에서 서버 뮤텍스로 방을 찾고, 4~6번에서 방 뮤텍스로 방 안의 일을 처리합니다.
- A: 서버 뮤텍스는 방 안의 데이터까지는 보호하지 않습니다.
- C: 멀티스레드 게임 서버는 잠금 범위를 방 단위로 설정하는 것이 적당합니다.
- D: 자주 잠그는 뮤텍스를 잠근 채로 파일을 액세스하면 성능 저하가 자주 발생합니다. 임계 영역은 꼭 필요한 범위로만 한정해야 합니다.
🔍 피드백: B를 정확히 골랐습니다. C(적당한 범위), D(성능 저하와의 관계) 근거도 맞습니다. A에서 “Nested Class의 객체도 보호했던 것 같다”고 헷갈려 하셨는데, 이 코드에서 Room은 자기만의 m_critSec을 따로 가지고 있고 4~6번에서 그 뮤텍스를 잠그므로, 서버 뮤텍스가 방 안의 데이터까지 보호하는 것이 아닙니다.
출처:
server/game_server/1/2025-06-13-game_server_1_11.md
Q3. 🟡 보통 — ⭕ 10/10
문제: 빈칸을 채우시오.
컴퓨터 네트워크의 품질과 특성에 대한 설명이다.
- 네트워크 품질을 평가하는 세 가지 기준은 전송 속도(스루풋), ①
___, 전송 지연 시간(레이턴시)이다. - 두 단말기 사이의 레이턴시는 그 사이에 있는 네트워크 기기들 각각의 레이턴시의 ②
___과 같다. (덧셈의 결과를 가리키는 말) - 두 단말기 사이의 스루풋은 그 사이에 있는 네트워크 기기들 중 ③
___스루풋과 같다. (크기 기준으로 “가장 큰 / 가장 작은” 중 어느 쪽인지를 나타내는 한 단어) - 와이파이(CSMA 방식)에서는 전파를 보내기 전 다른 기기의 전파가 감지되는지 확인하여, 감지되면 잠시 ④
___하고 감지되지 않으면 전파를 보낸다. (한 단어)
📝 내 답: 패킷 유실, 합, 가장 작은, 대기
정답:
① 패킷 유실률 ② 총합 (합) ③ 최소 (가장 작은) ④ 대기
해설:
네트워크 품질 기준은 전송 속도(스루풋), 패킷 유실률, 전송 지연 시간(레이턴시)입니다. 레이턴시는 경로상 네트워크 기기들의 레이턴시 총합이고, 스루풋은 경로상 기기들 중 최소 스루풋(가장 느린 구간, 병목)으로 결정됩니다. CSMA에서는 다른 전파가 감지되면 잠시 대기한 뒤 전파를 보냅니다.
🔍 피드백: 네 칸 모두 맞았습니다(각 2.5점). ①은 “패킷 유실”이라고 쓰셨는데, 품질 지표로서 같은 개념이라 정답으로 인정했습니다. 엄밀하게는 비율을 뜻하는 “패킷 유실률”이 정식 표현입니다.
출처:
server/game_server/2/2025-12-03-game_server_2_5.md
Q4. 🟢 쉬움 — ⭕ 10/10
문제: 다음 명제가 참(O)인지 거짓(X)인지 판단하라.
게임 서버의 기능을 여러 서버 인스턴스에 나누는 분산 처리를 많이 할수록 서버 인스턴스 간 역할 의존이 줄어들기 때문에, 클라우드 환경에서도 인스턴스 간 통신 회선의 신뢰성은 문제가 되지 않는다.
📝 내 답: X. 서버 인스턴스 간 역할 의존은 늘어날 수 있으며, 인스턴스 간 통신 회선의 신뢰성이 좋아야 한다.
정답: X
해설:
분산 처리가 많이 되어 서버 인스턴스 간 역할 의존이 많아지면 오히려 문제가 생길 수 있습니다. 클라우드 환경에서는 인스턴스 간 통신 회선의 신뢰성이 문제가 될 수 있고, 레이턴시가 크게 증가하거나 통신 불능이 되는 경우가 그 예입니다. 지나친 분산 처리는 네트워크 장비 과부하, 디버깅의 어려움 등도 낳습니다.
🔍 피드백: 판단(X)과 근거가 모두 정확합니다. 역할 의존이 줄어드는 것이 아니라 늘어난다는 점, 통신 회선 신뢰성이 중요해진다는 점을 둘 다 짚으셨습니다.
출처:
server/game_server/9/2026-03-20-game_server_9_9.md
Q5. 🔴 어려움 — 🔺 8.5/10
문제: C++ 반복자의 특성정보(traits) 클래스와 advance 함수 구현에 대해 답하시오.
(1) 특성정보는 포인터나 int 같은 기본 제공 타입에도 동작해야 한다. 그렇다면 특성정보를 타입 안에 넣는 방식이 안 되는 이유와, 대신 어디에 두어야 하는지를 쓰시오.
(2) 사용자 정의 반복자 타입(예: deque, list의 iterator)이 iterator_traits와 연결되려면 그 타입 안에 무엇을 두어야 하는가? 그리고 포인터 타입은 iterator_traits가 어떤 방식으로 지원하는가?
(3) 아래 코드는 iterator_traits<IterT>::iterator_category와 typeid를 if로 비교해 임의 접근 반복자를 구분하려 한다. 이 방식이 근본적으로 부적절한 이유를 “컴파일 도중”과 “런타임”이라는 표현을 사용해 설명하시오.
template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d) {
if (typeid(typename iterator_traits<IterT>::iterator_category)
== typeid(random_access_iterator_tag)) {
iter += d;
} else {
if (d >= 0) { while (d--) ++iter; }
else { while (d++) --iter; }
}
}
(4) 올바른 해결책은 doAdvance를 random_access_iterator_tag, bidirectional_iterator_tag, input_iterator_tag 매개변수별로 오버로딩하고, advance가 iterator_traits<IterT>::iterator_category()를 넘겨 호출하는 것이다. 이때 input_iterator_tag 버전의 doAdvance가 순방향 반복자(forward_iterator)도 받을 수 있는 이유는 무엇인가?
📝 내 풀이:
(1) 포인터나 int는 클래스가 아니기에 타입 안에 특성 정보를 넣을 수 없다. 대신 부분 템플릿 특수화를 통해 특성 정보를 가지도록 외부에 구현한다.
(2) *_iterator_tag 중 하나를 typedef를 통해 iterator_category로 연결시켜주어야 한다. 포인터 방식은 부분 템플릿 특수화를 통해 지원한다.
(3) 템플릿 메타 프로그래밍은 컴파일 도중 모든 템플릿 인스턴스를 생성한다. IterT와 if문도 검사하는데, 임의 접근 반복자에 해당하는 연산을 하다보니 컴파일 시점에서 에러가 발생한다.
(4) forward_iterator_tag가 input_iterator_tag를 상속하기 때문이다.
정답:
(1) 포인터나 int 같은 기본 제공 타입에는 특성정보를 넣을 수 없기 때문입니다. 따라서 특성정보는 타입의 외부에 존재해야 하며, 템플릿 및 그 템플릿의 1개 이상의 특수화 버전에 넣습니다. 반복자의 경우 표준 라이브러리의 특성정보용 템플릿이 iterator_traits입니다.
(2) 사용자 정의 반복자 타입 안에 iterator_category라는 이름의 typedef를 두어야 합니다(예: deque는 random_access_iterator_tag, list는 bidirectional_iterator_tag). 포인터 타입은 iterator_traits<IterT*>에 대한 부분 템플릿 특수화 버전을 제공하여 지원하며, 그 iterator_category는 random_access_iterator_tag입니다.
(3) IterT의 타입과 iterator_traits<IterT>::iterator_category는 컴파일 도중에 파악됩니다. 그런데 if문은 런타임에 평가됩니다. 즉, 주어진 타입에 대한 평가는 컴파일 도중에 해야 하는데 런타임 분기로 처리하려 했기 때문에 부적절합니다. (이 코드는 컴파일도 되지 않습니다.)
(4) 반복자 태그 구조체들이 is-a 관계로 상속되어 있기 때문입니다. forward_iterator_tag는 input_iterator_tag를 상속하므로, input_iterator_tag를 매개변수로 받는 doAdvance가 순방향 반복자도 받을 수 있습니다. 이것이 태그 사이에 상속 관계를 둔 이유입니다.
🔍 피드백:
- (1) 2.5/2.5 — 기본 타입에는 타입 안에 넣을 수 없다는 이유와, 외부의 템플릿 특수화에 둔다는 해법을 모두 맞혔습니다.
- (2) 2.5/2.5 —
iterator_categorytypedef와 포인터의 부분 템플릿 특수화를 정확히 답했습니다. (포인터의 카테고리가random_access_iterator_tag라는 점까지 쓰면 더 좋습니다.) - (3) 1/2.5 — “이 코드는 컴파일 에러가 난다”는 결과는 맞지만, 핵심 논점인 “타입 정보는 컴파일 도중에 알 수 있는데
if는 런타임에 평가된다”는 구분이 빠졌습니다. 에러가 나는 이유를+=가 임의 접근 반복자 전용이라는 것에서 찾으셨는데, 이는 증상이고, 근본 원인은 컴파일 도중 결정할 일을 런타임 분기로 처리하려 한 데 있습니다. 그래서 오버로딩(컴파일 도중 선택)으로 풀어야 합니다. - (4) 2.5/2.5 — 태그 간 상속(is-a)이 이유라는 점을 정확히 답했습니다.
출처:
game_dev/cpp/chapter7/2025-11-02-cpp_7_47.md
Q6. 🟡 보통 · 📌 오답노트 — 🔺 8.3/10
문제: 온라인 게임의 플레이어 정보 저장에 대해 답하시오.
(1) 어떤 게임이 골드와 인벤토리 정보를 클라이언트 쪽 파일에 저장한다고 하자. 이 방식의 문제점 두 가지를 쓰시오. 또한 반대로 클라이언트에 두어도 되는 사소한 데이터의 예를 두 가지 이상 쓰시오.
(2) 플레이어 A가 플레이어 B에게 아이템을 넘기는 거래는 “A의 인벤토리에서 아이템 제거 → B의 인벤토리에 아이템 추가” 두 단계로 이루어진다. 첫 단계만 끝나고 시스템이 중단되면 어떤 일이 생기는가? 이를 막아 주는 데이터베이스 기능의 이름과, 그 기능의 정의(“무엇의 최소 단위인가”)를 쓰고, 이 기능이 보장하는 성질의 이름을 쓰시오.
(3) 두 개 이상의 처리가 동시에 같은 데이터에 접근해 이상한 결과가 나오는 것을 데이터베이스에서는 무엇으로 막는가? 멀티스레드 프로그래밍의 어떤 개념과 비슷한지도 쓰시오.
(4) 시스템이 중단되더라도 원래 해야 했던 일들을 찾을 수 있게 해 주는 데이터베이스의 장치 이름과, 그것이 어떻게 동작하는지 한 줄로 쓰시오.
📝 내 풀이:
(1) 1. 클라이언트 측에서 골드와 인벤토리 정보를 조작할 수 있다, 다른 디바이스에서 플레이 시 해당 정보가 없다.
- 게임 내에서 로딩 시 필요한 에셋, 설정 정보들
(2) A에서 아이템이 사라지고, B에는 변화가 없어진다. 트랜잭션, 업무 처리 단위, 원자성
(3) 락, 레이스 컨디션
(4) 로그 버퍼. 로그를 기록해두었다가, 시스템 재개시 처리한다.
정답:
(1) 문제점: ① 해킹에 취약하다(클라이언트 측 데이터는 쉽게 조작 가능). ② 크로스 플랫폼 플레이가 불가하다(같은 사용자가 다른 기기를 쓸 때 이어서 할 수 없다). 클라이언트에 둬도 되는 사소한 데이터의 예: UI 설정, 그래픽 옵션, 키 설정(키 바인딩), 사운드 볼륨 중 두 가지 이상.
(2) 아이템이 A에게서는 사라졌는데 B에게는 추가되지 않아 아이템이 증발합니다. 이를 막는 기능은 트랜잭션이며, 논리적인 기능을 수행하기 위해 더 이상 분할할 수 없는 최소한의 업무 처리 단위입니다. 트랜잭션이 보장하는 성질은 원자성으로, 모두 성공하거나 모두 실패하도록 하여 중간 단계에서 되돌릴 수 있게 합니다.
(3) 락(Lock)으로 막습니다. 멀티스레드의 임계 영역과 비슷한 개념입니다.
(4) 로그 버퍼입니다. 데이터베이스가 데이터를 미리 기록해 두기 때문에, 시스템이 중단되더라도 원래 해야 했던 일들을 찾을 수 있습니다.
🔍 피드백:
- (1) 2/2.5 — 문제점 두 가지(조작 가능, 다른 기기에서 정보 없음)는 정확합니다. 사소한 데이터의 예는 “설정 정보”만 정답 범주(UI 설정·그래픽 옵션·키 설정·볼륨 등)에 맞고, “로딩 시 필요한 에셋”은 플레이어 정보와 성격이 달라 예로 보기 어렵습니다. 한 가지가 더 필요했습니다.
- (2) 2.5/2.5 — 아이템 증발 상황, 트랜잭션, 업무 처리 단위, 원자성 모두 맞습니다. (“더 이상 분할할 수 없는”이라는 수식어까지 붙이면 정의가 더 정확해집니다.)
- (3) 1.3/2.5 — 락은 맞지만, 비슷한 멀티스레드 개념으로 레이스 컨디션을 쓰신 것은 틀렸습니다. 레이스 컨디션은 막아야 할 “문제”이고, 락이 대응하는 개념은 공유 데이터를 한 번에 하나만 접근하게 하는 임계 영역입니다.
- (4) 2.5/2.5 — 로그 버퍼와 “기록해 두었다가 재개 시 처리한다”는 동작 설명이 모두 맞습니다.
출처:
server/game_server/4/2026-02-11-game_server_4_7.md오답노트:wn-4d40e435· 2026-09-15 최초 오답 · 이번이 2번째 복습
📌 복습 포인트
- Q1 프로그램 vs 프로세스의 메모리 구성 — 프로그램 파일은 코드·데이터만 가지고, 힙·스택은 프로세스가 될 때 추가됨 →
server/game_server/1/2025-04-25-game_server_1_1.md - Q5 traits와 advance — 타입에 따른 분기는 컴파일 도중 결정해야 하므로
if대신 태그 오버로딩을 쓰는 이유 →game_dev/cpp/chapter7/2025-11-02-cpp_7_47.md - Q6 플레이어 정보 저장과 DB — 클라이언트에 둬도 되는 데이터의 예, DB 락은 멀티스레드의 임계 영역에 대응 →
server/game_server/4/2026-02-11-game_server_4_7.md
댓글남기기