43. 백그라운드 워커의 수명 관리 부재 (Dispose 후 잔존 작업) (C#)
난이도 상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// [시나리오] 백그라운드 워커를 가진 매니저의 수명 관리 (서버 내부)
//
// ZoneManager 는 생성 시 백그라운드 루프를 띄워 주기적으로 내부 상태(틱 카운트·
// 통계 맵)를 갱신한다. 매니저가 더 이상 필요 없어 Dispose 되면 그 백그라운드
// 작업도 멈춰야 한다.
//
// [요구사항]
// - Dispose 이후 백그라운드 루프가 매니저의 상태에 더 이상 접근하면 안 된다.
// - 백그라운드 루프에서 던져진 예외가 조용히 사라지면 안 된다.
//
// [과제]
// 아래 코드를 리뷰하라. (A)(B) 지점의 동작을 근거로, Dispose 후 무슨 일이
// 일어나는지 재현과 함께 설명하고 수정안을 제시하라.
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
public class ZoneManager : IDisposable
{
private readonly Dictionary<int, long> _stats = new();
private long _tick;
public ZoneManager()
{
// (A) 생성자에서 this 를 캡처해 백그라운드 루프 시작
_ = Task.Run(RunLoop);
}
private async Task RunLoop()
{
while (true)
{
_tick++;
_stats[0] = _tick;
await Task.Delay(10);
}
}
public void Dispose()
{
// (B) 자원 정리
_stats.Clear();
}
} 결함 코드 · C++
// [시나리오] 백그라운드 워커를 가진 매니저의 수명 관리 (서버 내부)
//
// ZoneManager 는 생성 시 백그라운드 스레드를 띄워 주기적으로 내부 상태(틱 카운트·
// 통계 맵)를 갱신한다. 매니저가 파괴되면 그 스레드도 멈춰야 한다.
//
// [요구사항]
// - 매니저 파괴 후 백그라운드 스레드가 매니저 멤버에 접근하면 안 된다.
//
// [과제]
// 아래 코드를 리뷰하라. (A)(B) 지점의 동작을 근거로 매니저 파괴 후 무슨 일이
// 일어나는지 재현과 함께 설명하고 수정안을 제시하라.
#include <thread>
#include <unordered_map>
#include <chrono>
class ZoneManager {
std::thread worker_;
std::unordered_map<int, long> stats_;
long tick_ = 0;
void Run() {
while (true) {
tick_++;
stats_[0] = tick_;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
public:
ZoneManager() {
// (A) 생성자에서 this 를 캡처해 백그라운드 스레드 시작
worker_ = std::thread([this] { Run(); });
}
~ZoneManager() {
// (B)
worker_.detach();
}
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.