분명 shared_ptr은 레퍼런스 카운트가 스레드 안정적이라고 되어있다고 나와있지만 아래와같은 코드를 실행하면 실행하자마자 에러가 발생한다.
#include <memory> std::shared_ptr<int> g; DWORD WINAPI U(void *) { while (true) { std::shared_ptr<int> data = g; } return 0; } DWORD WINAPI C(void *) { while (true) { std::shared_ptr<int> data = std::make_shared<int>(0); g = data; } return 0; } int main() { HANDLE h1 = CreateThread(NULL, 0, U, NULL, 0, NULL); HANDLE h2 = CreateThread(NULL, 0, C, NULL, 0, NULL); WaitForSingleObject(h1, -1); WaitForSingleObject(h2, -1); return 0; }
거의 수시간동안 구글링해도 한결같이 나오는건 레퍼런스 카운트는 스레드 안전하다는 것 정도.
그래도 다행이도 계속 검색해보니 결국 아래와같이 atomic을 사용하는 코드가 나왔다.
#include <atomic> #include <memory> std::shared_ptr<int> g; DWORD WINAPI U(void *) { while (true) { std::shared_ptr<int> data = std::atomic_load(&g); } return 0; } DWORD WINAPI C(void *) { while (true) { std::shared_ptr<int> data = std::make_shared<int>(0); std::atomic_store(&g, data); } return 0; } int main() { HANDLE h1 = CreateThread(NULL, 0, U, NULL, 0, NULL); HANDLE h2 = CreateThread(NULL, 0, C, NULL, 0, NULL); WaitForSingleObject(h1, -1); WaitForSingleObject(h2, -1); return 0; }
저렇게 atomic_store, atomic_load를 사용하니 이제 정상적으로 shared_ptr 객체가 두 스레드간의 참조가 문제없이 되었다. 분명 부스트의 shared_ptr 기준으로 코드를 보면 InterlockedIncrement 함수를 사용하여 카운트하던데 그마저도 저런식으로 사용하니 0xDDDDDDDD로 채워진 이미 초기화 된 변수가 나타났다. 좀처럼 이해하기 힘든 동작이였다.
수시간, 그리고 며칠동안 구글링 아무리 해봐도 shared_ptr는 참조 카운트가 스레드 안전하다고 할 뿐 좀 더 자세한 내용 잘 나오지도않고(…) 그냥 이렇게 사용해야 정말 안전하다 정도로 알고 넘어가야겠다 -_-;;;