서버 공부

[서버 공부]4. Lock

myjeongjun 2025. 1. 2. 00:16

interlock은 정수만 사용가능하다는 제한사항이 존재 또한
단순 정수 더하기가아닌 코드가 길어졌을때 interlock를 이용해서 모든 작업을 동시다발적으로 접근을 막아주게 해주는데에는 한계가 명확함
그러므로 좀더 확장해서  어떤 영역자체를 스레드들이 동시 다발적으로 접근하면 안되게하는 기능을 지원한다. 이때 그 영역을 critical section(임계 영역)이라고 칭한다.

 

그리고 이러한 개념을 lock이라고 한다. 이 lock 의 개념을 도입하면 어떤 스레드가 접근했을대 다른 스레드는 접근을 막고 대기하게 할수있다(이것을 Mutual exclusion,상호배제라고한다.)

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ServerCore
{
    internal 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(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);
        }
    }
}

코드를 보면 누군가 Monitor.Enter에 먼저 접근하면 다른 스레드들은 대기상황을 해야하고 Monitor.Exit를 실행해야지만 다른 스레드들이 대기가 풀린다.

 

이렇게 일일이 Enter, Exit를 해주게되면 함수를 잘 구성하면 상관없겠지만, 그렇지않고 어느 지점에서 Exit를 하지않은채 return등을 이용해서 탈출해버리면 다른 스레드들은 무한 대기상태에 빠져버린다. 이것을 DeadLock이라고한다.

 

그러므로 lock 키워드를 사용해서 블록안에있는 연산이 끝나면 자동으로 Exit를 해준다.

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ServerCore
{
    internal class Program
    {

        static int number = 0;
        static object _obj = new object();

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

            }
                    
        }

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

        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);
        }
    }
}