최근 CppCon 유튜브 채널에서 Efficient Concurrent Memory Management라는 주제의 영상을 보게되었습니다. 내용은 멀티 스레드 환경에서 메모리를 안전(RAII)하게 사용하면서, 성능도 놓치지 않는 방법을 제시하는 영상이었습니다. 그리고 이러한 방법중 하나로 atomic shared_ptr을 이야기를 하고 있습니다. 그런데 개인적으로 shared_ptr를 Muti Thread 환경에서 사용한 경험이 많이 없어서, 이 영상을 보면서 꽤 흥미로운 부분들을 많이 알 수 있게 되었습니다. 따라서 오늘은 이 영상의 초반 부분에 해당하는 shared_ptr의 Multi Thread 상황에 대해서 이야기 해보겠습니다.
위 이미지는 Muti Thread 상황에서 얼마든지 발생할 수 있습니다. 그리고 이러한 상황은 shared_ptr를 통해서 해결이 가능할거 같습니다. 왜냐하면 shared_ptr는 referece count를 통해 RAII방식으로 Object를 관리하기 때문에 만약 위의 List가 shared_ptr로 관리되고 있었다고 하면, Thread1이 해당 객체를 참조하고 있는한, 객체가 삭제되어 발생하는 이슈들은 방지할 수 있습니다. 그런데 이 조건이 성립되기 위해서는 shared_ptr가 thread safety하다는 조건이 있어야 합니다.
cppreference에서 shared_ptr에 대해 이렇게 설명하고 있습니다. "shared_ptr의 제어 블록은 Thread로부터 안전하다." 이 뜻은 reference count를 update하는 부분은 atomic하게 동작하고 있고, 따라서 reference count가 0이 되어 객체를 삭제하는 작업도 정확히 한 번만 수행한다고 보장할 수 있습니다.
하지만, 위의 이미지 처럼 각각의 Thread에서 다른 Thread의 shared_ptr을 참조할 때, 이 객체가 s2 객체인지 아니면 other_thing 객체인지 단정지을 수 없습니다. 따라서 shared_ptr는 궁극적으로 thread safety하지 않다고 말할 수 있고, Muti Thread 상황에서 올바른 동작을 기대하려면 shared_ptr overloads of atomic functions을 사용해야 합니다.
그리고 atomic shared_ptr를 사용하면 정말 간단하게 thread safety한 자료 구조를 완성할 수 있습니다. 하지만 이와 반비례로 성능에서는 별로 좋지 못한 결과를 보여줍니다.
아래의 그래프는 BST를 atomic shared_ptr를 통해서 구현 했을때 와 Baseline(Delete가 없는 상황, 즉 Memory 관리가 전혀 필요없는 경우)를 비교한 것 입니다.
이 영상에서 발표자는 위 그래프를 그리기 위해서 사용한 atomic shared_ptr BTS는 자신이 알고 있는 가장 빠른 버전이라고 이야기 하고 있습니다. 하지만 Baseline에 비해 처리량이 현격히 떨어집니다.
위 이미지를 보면 이전의 그래프 결과를 바로 납득할 수 있습니다. 단지 w값을 읽기 위한 과정일 뿐이지만, reference count가 갱신되고 있음을 알 수 있습니다. 즉 reference count는 atomic하게 동작하여 값을 갱신할 것이고, 이 말은 각각의 Thread들이 Serialize되어 읽기만으로 엄청난 성능 하락을 보이게 됩니다.
Reference
std::shared_ptr - cppreference.com
std::shared_ptr - cppreference.com
template< class T > class shared_ptr; (since C++11) std::shared_ptr is a smart pointer that retains shared ownership of an object through a pointer. Several shared_ptr objects may own the same object. The object is destroyed and its memory deallocated when
en.cppreference.com
'C++' 카테고리의 다른 글
[삽질] runtime_error를 던질 때 segmentation fault 발생 (0) | 2023.02.28 |
---|---|
[빌드] C++ macro 빌드 에러 (Windows) (0) | 2023.02.22 |
[기본] C++ Exception에 대한 이해 (2) | 2023.02.04 |
[최적화] RVO, NRVO가 일어나지 않은 경우 (0) | 2023.02.01 |
[빌드] TensorFlow C++ 라이브러리를 빌드하는 과정에서 마주한 에러들 (0) | 2023.01.30 |