본문 바로가기
c#_게임서버

lock

by kcj3054 2022. 6. 30.

lock

  • c++에서는 mutext 개체를 사용해서, lock을 걸어주고 풀어주고 가능, c#에서는 monitor개념을 사용 (이것들은 mutual exclusive(상호 배제)라는 것이다..

예시..

using System;
using System.Threading;

namespace C_shop
{
    class Program
    {
        static int number = 0;
        static object _obj = new object();
        void Thread_1()
        {
            for(int i = 0; i < 1000; i++)
            {
                //try
                //{
                //    Monitor.Enter(_obj);
                //    number++;
                //}
                //finally
                //{
                //    Monitor.Exit(_obj);
                //}
                lock(_obj)
                {
                    number++;
                }
            }
        }

        void Thread_2()
        {
            try
            {
                Monitor.Enter(_obj);
                number--;
            }
            finally
            {
                Monitor.Exit(_obj);
            }
        }
        static void Main(string[] args)
        {

        }
    }
}
  • 위의 소스에서, Monitor.Exit(_obj)로 풀어주는 부분이 없으면 데드락이 발생한다. 그래서 try, finally로 묶어서 무슨일이 있어도 finally쪽은 실행되도록 만들어야한다..
  • 조금 코드가 더러워지면 간단한데 미리만들어진 lock을 사용하면된다.
 lock(_obj)
                {
                    number++;
                }

DeadLock

// See https://aka.ms/new-console-template for more information


Thread t1 = new Thread(Test);
Thread t2= new Thread(Test1);

t1.Start();
t2.Start();

t1.Join();
t2.Join();

Console.WriteLine("안녕");

void Test()
{
    for (int i = 0; i < 1000; i++)
    {
        SessionManager.Test();
    }
}

void Test1()
{
    for (int i = 0; i < 1000; i++)
    {
        UserManager.Test();
    }
}

class SessionManager
{
    private static object _lock = new();

    public static void TestSession()
    {
        lock (_lock)
        {

        }
    }

    public static void Test()
    {
        lock (_lock)
        {
            Console.WriteLine("SessionManager의 Test()");
            UserManager.TestUser();
        }
    }
}

class UserManager
{
    private static object _lock = new();

    public static void Test()
    {
        // UserManager의 Test를 건후,.. SessionManager의 TestSession를 건다.
        lock (_lock)
        {
            Console.WriteLine("UserManager의 Test()");
            SessionManager.Test();
        }
    }

    public static void TestUser()
    {
        lock (_lock)
        {

        }
    }
}

  • 위 DeadLock에서 t1.Join, t2,Join을 하게 된다면 "안녕"이 출력된다

    • 이유는 해당 t1, t2스레드가 끝날 때까지 기다려주지 않고 MainThread가 종료되기 때문입니다.
  • 위에서 각 t1, t2스레드를 1000번씩 돌리고 join을 걸어도 "안녕"이 출력된다면 데드락이 걸리지 않은 것이다.

    • 그렇지만 위에서 각 스레드를 1000번씩 돌려도 바로 데드락이 걸리게된다.
    • t1스레드는 Test를 실행하면서 SessionManager.Test()실행할 때 SessionManager의 lock을 획득한 후 UserManager의 lock을 사용한다.
    • t2스레드는 Test1을 실행하면서 UserManager.Test()를 실행하고 SessionManager의 Test를 실행하기 위해서 lock을 건다. 그래서 서로 상호 lock을 획득하면서 물러서지않는 형태이다..

'c#_게임서버' 카테고리의 다른 글

mmorpg서버구조  (0) 2022.07.06
spinlock, autoResetEvent, ReaderWriterLock  (0) 2022.07.02
소켓프로그래밍  (0) 2022.06.28
멀티쓰레드  (0) 2022.06.28
서버란?  (0) 2022.06.28