컴퓨터 프로그래밍 공부/네트워크 서버

SpinLock 구현 코드 및 추가 설명

뽀또치즈맛 2025. 3. 9. 03:34
class SpinLock
{
public:
    void Lock()
    {
        // CAS (Compare-And-Swap)

        // 기대값
        bool expected = false;
        // 설계된 값
        bool desired = true;

        // CAS 의사 코드
        //if (_locked == expected) {
        //    expected = _locked;
        //    _locked = desired;
        //    return true;
        //}
        //else
        //{
        //    expected = _locked;
        //    return false;
        //}

        while (_locked.compare_exchange_strong(expected, desired) == false)
        {
            expected = false;
        }

        
    }

    void unlock()
    {
        _locked.store(false);
    }

private:
    // atomic은 원자라는 단어에서 차용된 기능
    // 더 이상 실행 단위를 쪼갤 수 없기에 실행 단위를 하나의 흐름으로 본다
    // volatile 키워드는 atomic에 무조건적으로 포함되어 있는 기능이다.
    atomic<bool> _locked = false;
};

int32 sum = 0;
mutex m;
SpinLock spinLock;

스핀락 코드 설명

 

스핀락은 멀티스레드 환경에서

공유 자원의 접근을 제어하기 위한 간단한 동기화 기법이다.

 

한마디로 무한 존버단이다.

 

일반적인 뮤텍스와 달리 스레드를 대기 상태로 만들지 않고,

반복적으로 락 획득을 시도하는 바쁜 대기(busy-waiting) 방식을 사용한다.

 

 

스핀락 구현과 atomic의 관계

위 코드는

atomic<bool> 타입의 _locked 변수를 사용하여

락의 상태를 관리하며,

 

Lock() 함수에서는 CAS(Compare-And-Swap) 연산을 통해

_locked 값이 false일 때 true로 변경함으로써 락을 획득한다.

 

즉, atomic 변수는

여러 스레드가 동시에 접근하더라도 변수의 값이 일관되게 유지되며,

이로 인해 CAS(Compare-And-Swap) 연산과 결합하여

스핀락이 안전하게 동작할 수 있게 한다.

 

만약 다른 스레드가 이미 락을 가지고 있다면,

compare_exchange_strong() 호출은 실패하고

expected 값을 재설정하여 반복적으로 시도하게 된다.

 

unlock() 함수는 _locked를 false로 설정하여 락을 해제하며,

이로 인해 다른 스레드가 락을 획득할 수 있게 되는 로직이다.

 

스핀락의 특징

 

스핀락은 임계영역이 짧고,

스레드 전환 오버헤드를 줄이고자 할 때 유용하지만,

임계영역이 길어지면 CPU 자원을 낭비할 수 있으므로

상황에 맞게 신중하게 사용하자.