VisualStudio/C#서버

[C#서버][개념] 임계영역 Spin락(스핀락(SpinLock))

usingsystem 2022. 10. 26. 15:03
728x90

SpinLock- 무작정 기다리는 방법 (단점 cpu점유율이 많이올라감)
Context Switching - 소유권 포기후 다시접근하는 방법

AutoResetEvent - 운영체제 예약시스템으로 이벤트 사용하여 비어있으면 호출하여 접근

 

SpinLock

SpinLock은 C#에서 제공되는 스레딩 동기화를 위한 클래스 중 하나입니다. SpinLock은 다른 스레딩 동기화 메커니즘과 달리 스레드가 잠금 해제될 때까지 계속해서 "스핀"하면서 대기하는 방식으로 동작합니다. 스핀은 프로세서가 일정한 시간 동안 루프를 실행하면서 아무 일도 하지 않는 것을 말합니다.

SpinLock은 기본적으로 레커시브하지 않으며, 스핀을 사용하여 잠금을 획득하려고 시도합니다. 스핀락은 단일 프로세서 시스템에서는 효율적일 수 있지만, 다중 코어 시스템에서는 높은 확률로 스핀을 사용하는 것이 성능을 향상시킬 수 있습니다.

 

 점유하고자 하는 Rock이 점유가 풀릴때까지 계속 기다리는 방법(무한루프)으로 cpu점유율이 많이 올라가는 단점이 존재한다.

 

Interlocked.Exchange 사용방법(잘사용안함)

Interlocked.Exchange(ref _locked, 1)는 _locked의 이전 값을 전달해준다. 그래서 0을 반납할때 점유했다는 뜻이다.

  class SpinLock
    {
        volatile int _locked = 0;
        public void Acauire()//획득
        {
            while (true)
            {
                int original = Interlocked.Exchange(ref _locked, 1);
                if (original == 0)
                    break;
            }
        }
        public void Release()//반납
        {
            _locked = 0;
        }
    }

    internal class Program
    {
        static int _num = 0;
        static SpinLock _lock = new SpinLock();

        static void Thread_1()
        {
            for (int i = 0; i < 100000; i++)
            {
                _lock.Acauire();
                _num++;
                _lock.Release();
            }
        }
        static void Thread_2()
        {
            for (int i = 0; i < 100000; i++)
            {
                _lock.Acauire();
                _num--;
                _lock.Release();
            }
        }
        static void Main(string[] arg)
        {
            Task t1 = new Task(Thread_1);
            Task t2 = new Task(Thread_2);
            t1.Start();
            t2.Start();

            Task.WaitAll(t1, t2);

            Console.WriteLine(_num);
        }
    }

Interlocked.CompareExchange사용방법(일반적)

Interlocked.Exchange(ref _locked, 1)는 _locked의 이전 값을 전달해준다. 그래서 0을 반납할때 점유했다는 뜻이다.

    class SpinLock
    {
        volatile int _locked = 0;
        public void Acauire()//획득
        {
            while (true)
            {
                int expected = 0;//예상값
                int desired = 1;//결과값
                if(Interlocked.CompareExchange(ref _locked, desired, expected) == expected)//첫인자랑 세번째인자와 비교한후 가운데 인자로 반납한다.
                    break;
            }
        }
        public void Release()//반납
        {
            _locked = 0;
        }
    }

※Visualstudio에서 제공하는 SpinLock

기다리는 무한루프 중간에 한번씩 yeild기능을 수행하여 무한루프를 벗어나 다른 작업을 수행하는 장점이 있다.

즉 spinlock + contextSwitching 

 

  static SpinLock _lock = new SpinLock();
        static void Main(string[] arg)
        {
            bool lockTaken = false;
            try
            {
                _lock.Enter(ref lockTaken);
            }
            finally
            {
                if (lockTaken)
                    _lock.Exit();
            }
        }
728x90