본문 바로가기
게임 서버/[Inflearn_rookiss]올인원_클라&서버 연동

8. 스마트 포인터

by 헛둘이 2023. 12. 11.

스마트 포인터에 대한 내용이지만 결과적으로 스마트포인터의 동작이 멀티스레드 환경에서 어떻게 안전한지를 이해해야 하는 강의였다.
 

참조계수 관리 방식

- 참조계수 관리 방식이란 현재 해당 포인터가 참조된 횟수를 관리해서 0인 경우 메모리를 삭제하는 방식이다.
- 이 방식을 수동으로 관리하거나 자동으로 관리할 수 있는데, 스마트포인터는 이 참조계수를 자동으로 관리한다
- 수동으로 관리했을 때는 멀티스레드 환경에서 문제가 발생하는데, 스마트포인터를 사용하면 문제가 발생하지 않는다
그 이유에 대해 설명한다.
 

수동으로 관리했을 때의 문제점

- 수동으로 관리하는 것은 말그대로 필요에 따라 AddRef, ReleaseRef 함수를 통해 참조계수를 줄이고 늘림으로써 수동으로 관리하는 것이다.
- 1차적으로 캐치할 수 있는 문제는 AddRef나 ReleaseRef 내부에서 사용하는 연산이 ++, -- 연산인 경우이다.
- 이 경우에는 연산이 3단계로 수행되다보니 중간에 다른 스레드가 끼어들어 연산 결과가 정확하게 나오지 않을 수 있다.

eax = p;
eax = eax + 1;
p = eax

- 이 문제는 RefCount를 관리하는 변수를 atomic으로 선언함으로써 해결할 수 있다.
- 2차적으로 캐치할 수 있는 문제는 이 포인터가 어느 시점에 삭제될 지 알 수 없다는 것이다.
- 클래스의 포인터를 받는 함수에서 멤버 함수를 호출한다고 가정했을 때, 그 멤버함수가 호출되는 시점에 포인터가 살아있는가를 보장할 수 없다.
- 왜냐하면 멀티스레드환경이므로 그 순간 혹은 그 이전에 다른 스레드가 해당 포인터를 ReleaseRef했을 수도 있기 때문이다.
- 수동으로 관리하면 이 부분을 해결하기 어렵다.
 

자동으로 관리했을 때 해결되는 이유

- 자동으로 관리한다는 것은 스마트 포인터를 예시로 설명할 수 있다. (모든 포인터를 스마트 포인터로 사용한다는 전제)
- 스마트 포인터는 생성될 때, 복사 생성 혹은 대입 연산 등 내부 구현에서 AddRef를 호출하도록 한다
- 그리고 소멸되는 경우도 소멸자에서 ReleaseRef를 호출하도록 한다.
- 아까와 같이 해당 클래스의 스마트포인터를 받는 함수에서 멤버 함수를 호출한다고 가정했을 때 문제가 발생하지 않는다
- 왜냐하면 AddRef의 경우 복사생성자에서 호출되기 때문이다. (어차피 증감 연산은 atomic하게 이루어진다)
- 우려했던 점은 멤버 함수를 호출할 때 그 시점에 포인터가 살아있는지 여부를 확신할 수 없었다는 것인데 어차피 이 포인터는 이 함수를 호출한 스코프에서 소유하고 있을 것이다. (그 스코프가 아니더라도 지금 포인터가 살아있다는 것은 어딘가 소유하고 있어서 RefCount가 0이 아니기 때문)
- 그렇다면 당연히 제어권이 함수 내부로 넘어왔을 때 함수 내부에서 그 함수가 사라질리 없다(RefCount가 1 증가된데다가 내부에서 갑자기 ReleaseRef를 2번 호출하는 일이 발생하진 않을 것이기 때문)
- 더 정확히는 ReleaseRef를 호출하는게 수동이 아닌 자동으로 이루어지기 때문에 어떤 스레드가 이 포인터를 삭제하는 일은 일어나지 않는다 (왜냐하면 갑자기 참조계수를 감소시키는 코드를 넣을 필요가 없으니까)
 
 

'게임 서버 > [Inflearn_rookiss]올인원_클라&서버 연동' 카테고리의 다른 글

10. TCP vs UDP  (0) 2023.12.11
9. 소켓 프로그래밍  (0) 2023.12.11
7. 이벤트와 조건변수  (0) 2023.12.11
6. 데드 락  (0) 2023.12.11
5. 스핀 락  (0) 2023.12.11

댓글