이 글은 Inflearn - Rookiss : 게임서버 강의를 듣고 정리한 글입니다.

 

목차.

  1. 개요
  2. Monitor
  3. 데드락(DeadLock)
  4. Lock
  5. 정리

 

개요

 

멀티 스레드 환경에서 작업을 하다 보면 다양한 문제가 발생합니다.

멀티 스레드를 싱글 스레드와 같이 원자성을 보장토록 하려면 어떻게 해야 할까요?

 

다양한 방법들이 있지만 이번에는 Lock에 대해 다뤄보겠습니다.

 

Monitor

 

Monitor.Enter() / Monitor.Exit()

using System;
using System.Numerics;

namespace CSharp
{
    class Program {
        static int number = 0;
        static object _obj = new object();
        static void Thread_1() 
        {
            for (int i = 0; i < 100000; i++)
            {
                Monitor.Enter(_obj); //문을 잠군다
                number++;
                Monitor.Exit(_obj); //잠군 문을 푼다
            }
        }
        static void Thread_2()
        {
            for (int i = 0; i < 100000; i++)
            {
                Monitor.Enter(_obj);
                number--;
                Monitor.Exit(_obj);
            }
        }

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

            Task.WaitAll(t1, t2);

            Console.WriteLine(number);
        }
    }
}

 

Monitor.Enter()/ Monitor.Exit()
- 위 코드는 싱글 스레드와 같은 역할을 하게 해주는 코드입니다.

- Monitor.Enter() 코드가 실행되면 Monitor.Exit() 코드가 실행되기 전까지 다른 코드는 실행되지 않습니다.

* 마치 Enter가 실행되면 문을 닫고 Exit가 실행되면 문을 다시 여는 행위

 

만약 Monitor가 없다면 출력되는 number는 무작위가 되겠지만

해당 코드로인해 0이 출력될 것입니다.

 

장점

 Interlocked과는 달리 범위를 지정해서 잠글 수 있기 때문에 유용하게 사용이 가능

 

단점

코드가 길어질수록 관리가 어려워진다는 문제

 

데드락(DeadLock)

 

        static void Thread_1()
        {
            for (int i = 0; i < 100000; i++)
            {
                Monitor.Enter(_obj);
                {
                    number++;
                    return;
                }; //문을 잠군다

                Monitor.Exit(_obj); //잠군 문을 푼다
            }
        }

Thread_1 함수만 다음과 같이 수정하고 실행시키면 어떤 결과는?

 

무한히 실행된다.

 

Monitor.Enter를 한 뒤 return을 통해 종료되고Monitor.Exit는 호출되지 않은 상태

그 상태에서 Thread_2() 함수의 Monitor.Enter가 호출되면,

Monitor.Enter는 계속해서 기다리는 상태가 되기 때문에 무한히 실행되는 것입니다.

 

이런 상황을 데드락(DeadLock) 데드락(DeadLock)이라고 합니다

 

Lock

 

lock(조건){}

 static void Thread_1()
 {
     for (int i = 0; i < 100000; i++)
     {
         lock (_obj)
         {
             number++;
         }
     }
 }

내부적으로 Monitor.Enter와 Exit가 작동하기 때문에 코드를 비교적 더 간결하게 작성할 수 있습니다.

이제 스레드가 원자적으로 작동하며 문제가 발생하지 않습니다.

 

정리

 

이번 글에서는 Monitor를 이용했을 때 일어나는 문제와 데드락의 개념,

그리고 Lock을 사용하는 방법에 대해서 다뤄봤습니다.

 

+ Recent posts