51. 재사용 배리어의 세대(phase) 관리 부재로 인한 프레임 섞임·데드락 · C#
난이도 최상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// 시나리오: 틱 루프 워커 동기화용 재사용 배리어 (C#)
//
// 게임 서버의 틱 루프는 N개의 워커 스레드가 매 프레임 각자 일부 엔티티를 갱신한 뒤,
// 모두 끝날 때까지 만나서 기다렸다가(rendezvous) 다음 단계(충돌 판정 등)로 넘어간다.
// 이 만남을 위해 매 프레임 재사용되는 배리어를 직접 구현했다.
//
// 각 워커는 프레임마다 SignalAndWait() 를 호출한다. 모든 워커(_parties 명)가
// 도착하면 함께 풀려나 다음 프레임을 시작한다. 배리어는 여러 프레임에 걸쳐 재사용된다.
//
// 요구사항:
// - 매 프레임, 모든 워커가 도착해야 아무도 다음 단계로 못 넘어간다(정확한 rendezvous).
// - 배리어는 프레임마다 다시 쓸 수 있어야 한다.
//
// 워커 수는 4, 프레임은 수천 번 반복된다고 하자.
//
// 과제:
// 1) (A)(B) 를 중심으로, 배리어를 프레임마다 재사용할 때 무엇이 깨지는지 설명하라.
// 2) 특정 인터리빙에서 정확성이 어떻게 깨지는지(일부 워커 멈춤 또는 정족수 미달 통과) 제시하라.
// 3) 수정안을 제시하라.
using System.Threading;
public class TickBarrier
{
private readonly int _parties;
private int _waiting = 0;
private readonly object _gate = new object();
public TickBarrier(int parties) { _parties = parties; }
public void SignalAndWait()
{
lock (_gate)
{
_waiting++;
if (_waiting == _parties)
{
// 마지막 도착자: 다음 프레임을 위해 리셋하고 전원 깨움
_waiting = 0; // (B)
Monitor.PulseAll(_gate);
}
else
{
// 아직 다 안 왔으면 리셋될 때까지 대기
while (_waiting != 0) // (A)
Monitor.Wait(_gate);
}
}
}
} 결함 코드 · C++
// 시나리오: 틱 루프 워커 동기화용 재사용 배리어 (C++ 게임서버)
//
// N개의 워커 스레드가 매 프레임 각자 일을 끝낸 뒤 만나서 기다렸다가 함께 다음
// 단계로 넘어간다. 이 rendezvous 를 위해 매 프레임 재사용되는 배리어를 직접 구현했다.
//
// 각 워커는 프레임마다 arriveAndWait() 를 호출한다. 모든 워커(parties_ 명)가
// 도착하면 함께 풀려나고, 배리어는 다음 프레임에 다시 쓰인다.
//
// 요구사항:
// - 매 프레임 모든 워커가 도착해야 아무도 다음 단계로 못 넘어간다.
// - 배리어는 프레임마다 재사용 가능해야 한다.
//
// 과제:
// 1) (A)(B) 를 중심으로 프레임마다 재사용할 때 무엇이 깨지는지 설명하라.
// 2) 정확성이 깨지는(일부 워커 멈춤 또는 정족수 미달 통과) 인터리빙을 제시하라.
// 3) 수정안을 제시하라. g++ -std=c++17 -pthread 로 컴파일된다고 가정한다.
#include <mutex>
#include <condition_variable>
class TickBarrier {
public:
explicit TickBarrier(int parties) : parties_(parties) {}
void arriveAndWait() {
std::unique_lock<std::mutex> lk(mtx_);
++waiting_;
if (waiting_ == parties_) {
// 마지막 도착자: 리셋하고 전원 깨움
waiting_ = 0; // (B)
cv_.notify_all();
} else {
// 아직 다 안 왔으면 리셋될 때까지 대기
cv_.wait(lk, [this]{ return waiting_ == 0; }); // (A)
}
}
private:
int parties_;
int waiting_ = 0;
std::mutex mtx_;
std::condition_variable cv_;
};
int main() { return 0; } 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.