[Thread] 동기화 / 임계 영역 ( Interlocked, Lock, Moniter )

22330 단어 CSThreadCS

🚀 동기화의 개념

멀티 스레드 환경에서는 여러개의 스레드가 하나의 공유 데이터를 사용하기에 하나의 스레드에서 데이터를 저장하는 동안 다른 스레드에서 데이터를 읽거나 그 반대의 경우처럼 여러가지 문제가 생길 수 있다. 따라서 데이터를 저장하는 동안에는 데이터를 읽지 못하게 해야하고, 데이터를 읽는 동안에는 데이터를 쓰지 못하도록 해야한다. 이 때 필요한 개념은 한 쓰레드가 작업 중 다른 쓰레드에 의해 간섭을 받지 못하도록 막는 쓰레드의 동기화이다.
동기화는 임계 영역에서 스레드들이 순서를 갖춰 자원을 사용한다.

🚀 동기화 방법

🔥 Interlocked

  • C#의 Interlocked는 다중 스레드에서 공유하는 변수에 대해 원자 단위 연산을 제공한다.

  • 임계 구역내의 고유 자원의 변수에 대한 원자성을 보장한다는 것이다

여기서의 원자성이란 모두 실행되던지, 모두 실행되지 않도록 하던지를 보장하는 특성이다.


        static int num = 0;
        static void Main(string[] args)
        {
            Task t1 = new Task(Thread1);
            Task t2 = new Task(Thread2);
            t1.Start();
            t2.Start();

            Task.WaitAll(t1, t2);

            Console.WriteLine(num);
        }

        static void Thread1()
        {
            for(int i = 0; i< 1000000; i ++)
            {
                num++;
            }
        }

        static void Thread2()
        {
            for (int i = 0; i < 1000000; i++)
            {
                num--;
            }
        }

위의 코드에서는 공유 자원인 num을 두 개의 스레드가 접근한다. 첫번째 스레드는 백만번 1을 증가시키고 두번째 스레드는 백만번 1을 감소시키기에 두 스레드가 끝날 시 num의 값은 0이 될 것으로 예상할 수 있지만,

실제로는 엉뚱한 값이 출력되게 된다. 그 이유는 두 개의 스레드가 병렬적으로 진행되기에 자원의 원자성을 보장받지 못하기 때문이다. 따라서 공유 자원인 num에 interlocked를 이용해 원자성을 보장해주어야 한다.

 static int num = 0;
        static void Main(string[] args)
        {
            Task t1 = new Task(Thread1);
            Task t2 = new Task(Thread2);
            t1.Start();
            t2.Start();

            Task.WaitAll(t1, t2);

            Console.WriteLine(num);
        }

        static void Thread1()
        {
            for(int i = 0; i< 1000000; i ++)
            {
                Interlocked.Increment(ref num);
            }
        }

        static void Thread2()
        {
            for (int i = 0; i < 1000000; i++)
            {
                Interlocked.Decrement(ref num);
            }
        }

위의 코드 처럼 Interlocked 클래스의 Increment와 Decrement를 통해 원자성을 보장해주었다.

이 때의 실행결과는 예상했던 값과 그대로 0이 출력되는 것을 볼 수 있다.

🔥 Lock

  • 상호 배제 잠금을 획득하여, 블럭 실행 후 잠금을 해제한다.
  • 다른 스레드에서는 잠금 획득이 차단되고, 잠금이 해제될 때 까지 대기 한다
class Program
    {
        static int Count = 0;

        static System.Object lockThis = new System.Object();
        
        static void Print()
        {
            lock (lockThis)
            {
                for(int i =0; i< 5; i++)
                {
                    Count++;
                    Console.WriteLine(Count);
                }
            }
        }
        static void Main(string[] args)
        {
            Thread thread1 = new Thread(new ThreadStart(Print));
            Thread thread2 = new Thread(new ThreadStart(Print));
            Thread thread3 = new Thread(new ThreadStart(Print));
            Thread thread4 = new Thread(new ThreadStart(Print));

            thread1.Start();
            thread2.Start();
            thread3.Start();
            thread4.Start();
        }

    }

  • 하나의 스레드에서 잠금이 풀릴 때 까지 다른 스레드에서는 대기하고 있다가 잠금이 풀리면 실행되는 것을 볼 수 있다

🔥 Moniter

  • Moniter 또한 lock과 마찬가지로 코드 블록이 여러 스레드에서 동시에 실행되지 않도록 방지한다

class Program
    {
        static int Count = 0;

        static System.Object moniterlock = new System.Object();
        
        static void Print()
        {
            Monitor.Enter(moniterlock);

            try
            {
                for(int i = 0; i<5; i++)
                {
                    Count++;

                    Console.WriteLine(Count);
                }
            }

            finally
            {
                Monitor.Exit(moniterlock);
            }
        }
        static void Main(string[] args)
        {
            Thread thread1 = new Thread(new ThreadStart(Print));
            Thread thread2 = new Thread(new ThreadStart(Print));
            Thread thread3 = new Thread(new ThreadStart(Print));
            Thread thread4 = new Thread(new ThreadStart(Print));

            thread1.Start();
            thread2.Start();
            thread3.Start();
            thread4.Start();
        }

    }
    

Ref https://www.hanbit.co.kr/network/category/category_view.html?cms_code=CMS1669525805
https://neohtux.tistory.com/220?category=620074
https://scvtwo.tistory.com/67

좋은 웹페이지 즐겨찾기