본문 바로가기
프로그래밍/Game Dev

[C#] AutoResetEvent

by YuminK 2023. 8. 26.

AutoResetEvent는 키를 얻고 문을 닫는(다른 스레드 접근 불가) 처리를 자동으로 진행해준다. 

 

class Lock
{
    // 문을 닫는 행위를 자동으로 해준다. 커널 단위의 실행. SpinLock은 커널에 요청하지 않음
    AutoResetEvent _available = new AutoResetEvent(true);

    public void Acquire()
    {
        _available.WaitOne(); // 입장 시도
    }

    public void Release()
    {
        _available.Set(); // flag = true
    }
}

class ThreadProgram
{
    static int _num = 0;
    static Lock _lock = new Lock();

    static void Thread_1()
    {
        for(int i = 0; i < 10000; ++i)
        {
            _lock.Acquire();
            _num++;
            _lock.Release();
        }
    }
    static void Thread_2()
    {
        for (int i = 0; i < 10000; ++i)
        {
            _lock.Acquire();
            _num--;
            _lock.Release();
        }
    }

    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 = " + _num);
    }
}

 

ManualResetEvent 사용시, 정상적으로 동작하지 않는다. 

로직이 원자성을 보장하지 않기 때문이다. 

class Lock
{
    // 문을 닫는 행위를 자동으로 해준다. 
    ManualResetEvent _available = new ManualResetEvent(true);

    public void Acquire()
    {
        // 원자적 처리가 안 되서 문제가 발생한다. 
        _available.WaitOne(); // 입장 시도
        _available.Reset(); // 문을 닫는다. 
    }

    public void Release()
    {
        _available.Set(); // flag = true
    }

}

 

뮤텍스 버전

class ThreadProgram
{
    static int _num = 0;
    static Mutex _lock = new Mutex();

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

 

SpinLock과 AutoResetEvent 방식의 차이

SpinLock 커널에 요청하는 동작이 아니지만, AutoResetEvent는 커널에 요청한다. 

커널에 요청하는 동작이 더욱 많은 리소스를 소비한다. 

 

'프로그래밍 > Game Dev' 카테고리의 다른 글

[Node.js] 간단한 멀티 슈팅게임 소스 분석  (0) 2023.09.26
[C#] Thread Local Storage  (0) 2023.08.28
[C#] SpinLock  (0) 2023.08.26
[C#] Interlocked  (0) 2023.08.26
[C#] MessagePack  (0) 2023.08.26

댓글