VisualStudio/C#서버

[C#서버][개념] 임계영역(크리티컬섹션)원자성 - 레이스컨디션(Race Condition)과 Interlocked

usingsystem 2022. 10. 26. 13:48
728x90

Rock처리와 함께사용

레이스컨디션

아래와 같은 소스코드를 실행할 경우 결과값은 0이아닌 다른 다양한 수로 출력된다. 이를 레이스 컨디션이라고 한다.

number ++를 할경우 보여지기에는 한 단계로 진행될 것 같지만 사실 어셈블리상으로는 아래 소스와 같이 3단계로 나뉘어 지기 때문에 0이아닌 결과가 나타나게된다.

 static int number =0;

        static void Thread_1()
        {
            for (int i = 0; i < 100000; i++)
            {
                //number++;를 어셈블리어로 풀어서 본다면 아래 소스와 같다.

                int temp = number;
                temp += 1;
                number = temp;
            }
        }

        static void Thread_2()
        {
            for (int i = 0; i < 100000; i++)
            {
                // number--;를 어셈블리어로 풀어서 본다면 아래 소스와 같다.
                int temp = number;
                temp -= 1;
                number = temp;
            }
        }

        static void Main(string[] args)
        {
            Task t1 = new Task(Thread_1);
            Task t2 = new Task(Thread_2);
            t1.Start();
            t2.Start();

            Task.WaitAll(t1, t2);
            Console.WriteLine(number);
        }

Interlocked을 사용하면 원자성을 보존할 수 있다.

성능이 빠르고 우수하나 정수만 사용할 수 있다는 단점이 존재한다. 또 한 몇십 몇백줄을 다 인터락을 사용해서 만들기 힘들다. 

Increment - 1씩 증가

Decrement - 1씩 감소

static void Thread_1()
        {
            for (int i = 0; i < 100000; i++)
            {
                Interlocked.Increment(ref number);  
            }
        }

        static void Thread_2()
        {
            for (int i = 0; i < 100000; i++)
            {
                Interlocked.Decrement(ref number);
            }
        }

CompareExchange - 예상값 결과 값을 비교

while (true)
            {
                int expected = 0;//예상값
                int desired = 1;//결과값
                //첫인자랑 세번째인자와 비교한후 가운데 인자로 반납한다. 즉시 반납 아님 다음 루프때 _locked에 값 적용
                if(Interlocked.CompareExchange(ref _locked, desired, expected) == expected)
                    break;
            }

Exchange - 2번쨰 인자 값으로 _flag값 변경 

 

  Interlocked.Exchange(ref _flag, EMPTY_FLAG);
728x90