공부하게된 계기
게임 서버를 구현하면서 동기화 이슈가 상당히 큰 비중을 차지한다는 것을 공부할수록 느끼게 됩니다.
멀티 스레드 프로그래밍에서 교착 상태(DeadLock)에 빠지게 되면 멀티 스레드 방식이 오히려 독이 될 수 있습니다.
이런 문제를 해결하기 위해 실행 순서를 제어하는데 이런 기술을 동기화(Synchronization)이라고 합니다.
여기까지는 게임 서버 강의를 들으면서 알고 있던 내용이였지만,
이번에 유저 모드와 커널 모드 동기화가 따로 있다는 것을 알게 되었습니다.
OS에 대한 공부와 C#에서는 어떤 방식의 동기화를 지원하는지 알아볼 수 있는 좋은 기회라고 생각해서 이렇게 글로 정리하게 되었습니다.
유저 모드 동기화란?
컴퓨터 시스템에서 운영 체제 커널 모드(커널 레벨)가 아닌,
유저 모드(유저 레벨)에서 실행 중인 응요 프로그램 또는 프로세스에서의 동기화 기법을 사용하는 것을 말합니다.
유저 모드 동기화는 커널 모드로의 전환을 최소화 하고 성능을 향상시키기 위해 주로 사용합니다.
유저 모드 동기화 종류
- 크리티컬 섹션(Critical Section, 임계 영역) 기반 동기화
- 공유 데이터(메모리)에 접근하는 코드 영역을 동기화하기 위한 방법입니다.
- 한 번에 하나의 스레드만 크리티컬 섹션에 들어갈 수 있으며, 다른 스레드는 대기해야 합니다(상호 배제).
- 데이터의 일관성과 무결성을 보장할 수 있습니다.
- MS Docs - Monitor 클래스 자료 => 링크
- csharpstudy.com - Monitor 클래스 자료 => 링크
- 인터락(Interlocked) 함수 기반 동기화
- 메모리 접근 동기화에 사용합니다.
- 원자적(Atomic) 연산을 수행하도록 보장하며, 여러 스레드가 동시에 접근하는 경우에도 데이터의 일관성을 유지합니다.
- 인터락 함수는 함수 내부적으로 동기화를 처리하므로 함수를 호출하는 스레드들 간에 서로 겹치지 않고 실행되도록 보장합니다.
- 주로 전역 변수 또는 공유 데이터에 대한 접근을 동기화하는 데 사용됩니다.
- MS Docs - Interlocked 클래스 자료 => 링크
크리티컬 섹션(임계 영역) 기반 동기화는 C#에서 Monitor 클래스를 사용한 동기화 방법과 유사합니다.
임계 영역에 대한 초입 부분을 Enter() 함수를 사용해 작성하고,
임계 영역에 대해 끝나는 부분을 Exit() 함수를 사용해 작성합니다.
인터락 동기화 방법도 C#에서 내부 함수로 이미 구현이 되어 있습니다.
해당 함수에 대한 정보와 예제 코드가 잘 정리되어 있는 링크를 같이 첨부했습니다.
커널 모드 동기화란?
운영 체제 커널 레벨에서 실행 중인 코드 또는 프로세스 간에 동시 접근으로 인한 충돌을 방지하고, 리소스를 안전하게 관리하기 위해 사용되는 동기화 기법을 의미합니다.
커널 모드 동기화 종류
- 뮤텍스(Mutex)
- C# MS Docs 자료 => 링크
- csharpstudy.com 자료 => 링크
- 세마포어(Semaphore)
- C# MS Docs 자료 => 링크
- csharpstudy.com 자료 => 링크
- 이벤트(Event)
- AutoResetEvent
- C# MS Docs 자료 => 링크
- csharpstudy.com 자료 => 링크
- ManualResetEvent
- C# MS Docs 자료 => 링크
- csharpstudy.com 자료 => 링크
- CountdownEvent
- C# MS Docs 자료 => 링크
- csharpstudy.com 자료 => 링크
C#에서는 이런 커널 모드 동기화를 좀 더 간편하게 구현할 수 있도록 내부 함수를 제공해줍니다.
이런 함수들에 대해 잘 정리되어 있고, 신빙성이 높은 MS Docs와 csharpstudy.com 이라는 사이트의 링크를 첨부했습니다.
각각 예제 코드와 개념이 잘 정리되어 있어서 어떻게 사용하는지 잘 나와있습니다.
커널 모드 동기화를 사용하는 이유
- 스레드가 CPU를 낭비하지 않도록 합니다.
- 스레드간 대기 및 스케줄링을 효율적으로 관리하므로 스레드가 무한히 CPU를 점유하지 않고 다른 작업을 수행할 수 있도록 합니다.
- 멀티 프로세서 시스템에서의 스레드 간에도 동기화를 할 수 있습니다.
- 운영체제 커널에서 처리를 하기 때문에 같은 컴퓨터의 다른 프로세서의 스레드 간에도 동기화가 가능합니다.
- 보안
- 커널 모드의 보안 체계를 이용해 권한이 없는 접근을 방지하고 자원에 대한 안전한 접근을 보장합니다.
- 타임 아웃 시간을 지정하여 스레드를 블로킹 할 수 있음
- 스레드가 일정 시간 동안 대기하다가 특정 조건이 충족되지 않으면 블로킹되도록 할 수 있습니다.
작성하면서 느낀 점
C#에서는 상당히 많은 것들이 이미 내부 함수로 구현되어 있고,
그것을 쉽게 사용할 수 있다는 것을 알게되었습니다.
하지만 이런 동기화 관련 함수를 무턱대고 사용하면 성능 이슈와 심하면 데드락이 발생할 수 있다는 것을 알게되었습니다.
그리고 게임 서버 강의를 들으면서 커널 모드인 뮤텍스(Mutex)를 우선 사용하지 말라고 했던 강사분의 의도도 알게 되었습니다.
아직 의문이 드는 것은 뮤텍스(Mutex)와 같은 커널 모드 동기화는 실제 어디서 사용하는지 궁금해졌습니다.
참고 자료
- 단순동기화3 - 커널 모드 동기화 => 링크
- Network Programming - 쓰레드 동기화 기법의 분류, 유저모드 크리티컬 섹션(CRITICAL_SECTION), 커널모드 Mutex(Mutual Exclusion) Semaphore 등 => 링크
- Lock Free 알고리즘(Non-Blocking 알고리즘) => 링크