Unity

[인프런 강의 정리] Context Switching, AutoResetEvent

wny0320 2024. 9. 27. 21:56

이 글은 아래 강의를 정리한 글이다

 

[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버 강의 | Rookiss - 인프런

Rookiss | 네트워크/멀티쓰레드/운영체제 등 핵심 전공 지식을 공부하고 게임 서버를 바닥부터 만들어보면서 MMORPG 기술을 학습하는 강의입니다., MMORPG 개발에 필요한 모든 기술, C# + Unity로 Step By St

www.inflearn.com

해당 정리글을 한번에 보고 싶다면 아래 링크를 참조하길 바란다

 

[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버 | Notion

서버OT

mesquite-prune-8c9.notion.site


// 쓰레드를 쉬다 오게 하는 방법 3가지
Thread.Sleep(1);
// 무조건 1ms 휴식
// 실제시간은 운영체제의 스케쥴러가 관리
Thread.Sleep(0);
// 조건부 양보
// 나보다 우선순위가 낮은 애들한테는 양보 불가
// 나보다 높은 우선 순위가 없으면 다시 본인이 작업
Thread.Yield();
// 관대한 양보
// 지금 실행이 가능한 쓰레드가 있으면 실행
// 실행 가능한 쓰레드가 없다면 남은 시간 소진

위 코드에서 쓰레드가 다른 쓰레드에게 양보하는 것을 배웠는데, 이 때 소모되는 비용에 대해 알아보자

Context Switching

  • 유저 영역의 프로그램 쓰레드끼리 스위칭을 하기 위해서는 커널 영역의 cpu코어를 거쳐야함
  • 레지스터는 다양한 레지스터가 존재함, RAM에서 그 프로그램에 필요한 데이터들을 뽑아서 일부는 레지스터에 복원하게 됨
  • 양보를 하게 되면 이런식으로 비용이 발생하게 됨
  • 따라서 어느게 효율적인지는 생각을 해봐야한다

Auto Reset Event

  • 자동으로 잠김

Manual Reset Event

  • 수동으로 잠김
class Lock
{
    AutoResetEvent _available = new AutoResetEvent(true);
    // 커널 레벨에서의 bool과 같음
    // 매개변수는 bool, 생성시 lock을 한 상태인지 아닌지 정함
    // spinlock보다 확연히 오래 걸리는걸 확인할 수 있음
    public void Acquire()
    {
        _available.WaitOne();
        // _available.Reset(); // => bool = false 넣는 과정과도 같음
        // 이 과정이 WaitOne에 포함
        // 입장 시도
        // 성공시 자동 잠금
    }
    public void Release()
    {
        _available.Set();
        // flag = true
    }
}
class Lock
{
    ManualResetEvent _available = new ManualResetEvent(true);
    // 이 기능은 한 번에 하나만 받을 필요가 없을 때 사용
    public void Acquire()
    {
        _available.WaitOne();
        _available.Reset(); // 문을 닫는 개념
        // 결국 이 문제들은 문이 잠겨있는지 확인하고 들어가서 닫는게 하나로 되어있지 않아서 문제
    }
    public void Release()
    {
        _available.Set(); // 문을 열어주는 개념
    }
}
using System;
using System.Threading;
using System.Threading.Tasks;

namespace ServerCore
{
    class Program
    {
        static int _num = 0;
        static Mutex _lock = new Mutex();
        // spinlock에 비해 느림
        // 느린 이유는 아까와 같이 커널 영역에서 돕기 때문
        // event들과 차이점
        // 몇 번 잠궜는지 정보가 있어서 그 만큼 해제를 해야지 잠금이 해제됨
        // ThreadId 를 가지고 있어서 잠금을 한 쓰레드를 기억하고 있다가 다른 쓰레드가 접근할 때 잡아주기도 함

        static void Thread_1()
        {
            for (int i = 0; i < 100000; i++)
            {
                _lock.WaitOne();
                _num++;
                _lock.ReleaseMutex();
            }
        }

        static void Thread_2()
        {
            for (int i = 0; i < 100000; i++)
            {
                _lock.WaitOne();
                _num--;
                _lock.ReleaseMutex();
            }
        }
        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(_num);
        }
    }
}