40. 손수 짠 스핀락의 비원자 획득(check-then-set)으로 깨지는 상호 배제 (C#)
난이도 상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// 시나리오: 핫패스용 손수 짠 스핀락(spinlock)
//
// 초당 수십만 번 갱신되는 아주 짧은 임계구역(카운터/작은 상태)을 뮤텍스보다 가볍게
// 보호하려고 스핀락을 직접 구현했다. 여러 스레드가 이 락으로 공유 카운터를 늘린다.
//
// 요구사항:
// - 임계구역에는 한 번에 한 스레드만 들어가야 한다(상호 배제).
// - N개 스레드가 각각 K번 증가시키면 최종 카운터는 정확히 N*K 여야 한다.
// - 락으로 보호된 쓰기는 다음에 락을 잡는 스레드에게 온전히 보여야 한다.
//
// 아래 스핀락 구현의 (A)(B) 지점을 검토하라.
using System.Threading;
public sealed class SpinLockNaive
{
private volatile bool _locked;
public void Enter()
{
while (_locked) { } // (A) 잠겨 있으면 풀릴 때까지 스핀
_locked = true; // 비었으니 내가 잡는다
}
public void Exit()
{
_locked = false; // (B)
}
}
public sealed class Counter
{
private readonly SpinLockNaive _lock = new SpinLockNaive();
private long _value;
public void Increment()
{
_lock.Enter();
_value = _value + 1; // 임계구역
_lock.Exit();
}
public long Value => _value;
} 결함 코드 · C++
// 시나리오: 핫패스용 손수 짠 스핀락(spinlock) (C++)
//
// 아주 짧은 임계구역을 뮤텍스보다 가볍게 보호하려고 스핀락을 직접 구현했다.
// 여러 스레드가 이 락으로 공유 카운터를 늘린다.
//
// 요구사항:
// - 임계구역에는 한 번에 한 스레드만 들어가야 한다(상호 배제).
// - N개 스레드가 각각 K번 증가시키면 최종 카운터는 정확히 N*K 여야 한다.
// - 락으로 보호된 쓰기는 다음에 락을 잡는 스레드에게 온전히 보여야 한다.
//
// 아래 스핀락 구현의 (A)(B) 지점을 검토하라.
#include <atomic>
class SpinLockNaive {
public:
void lock() {
while (locked_.load(std::memory_order_relaxed)) { } // (A) 확인
locked_.store(true, std::memory_order_relaxed); // 설정
}
void unlock() {
locked_.store(false, std::memory_order_relaxed); // (B)
}
private:
std::atomic<bool> locked_{false};
};
// N개 스레드가 각각 K번 이 카운터를 늘린다.
class Counter {
public:
void increment() {
lock_.lock();
value_ = value_ + 1; // 임계구역
lock_.unlock();
}
long value() const { return value_; }
private:
SpinLockNaive lock_;
long value_ = 0;
};
int main() { Counter c; c.increment(); return 0; } 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.