동시접근(쓰레드)에서 안전함을 위해 코딩의 방법과 시기를 알라.


다중쓰레드 환경에서 string의 안전성


쓰레드 안전성에 대해 공부하기 전에 우선 COW에 대해 먼저 알아보자.


COW(Copy-On-Write)란 데이터 하나를 여러 개체에서 공유해서 사용할 수 있도록 하는 기법이다.

string에서는 같은 문자 시퀀스를 여러 곳에서 복사해서 사용할 확률이 놓으므로 COW를 이용해 여러 string 개체에서 문자 시퀀스를 공유한다면 메모리 사용량이 줄어들고, 메모리 자우너 할당과 실제의 deep copy 과정이 생략될 수 있으므로 그만큼 이익이 된다. 자원 할당은 전통적으로 비싼 연산 중 하나로 인식되어 왔고, 복사를 위한 접근과 복사 또한 그에 못지 않은 성능 저하의 원인으로 지목되어 왔기 때문이다. COW는 읽기 전용으로 데이터를 공유하기 때문에 만일 공유 데이터를 사용하는 어떤 string이 데이터를 변경하면 그 string에서는 그제서야 자신만의 공간을 할당하고 데이터를 복사해서 사용한다. 이를 늦은 복사(lazy copy)라고 한다.


std::string str1("test");

std:string str2 = str1.c_str();

if(str1.c_str() == str2.c_str())

  std::cout << "Copy On Write" << std::endl;


위 예에서 &str1 != &str2는 당연히 성립한다.

str1.c_str() == str2.c_str()은 어떨까?

수식이 성립할 수도 있고 성립하지 않을 수도 있다. 표준에서는 위 사항에 대해 정의하고 있지 않기 때문이다.

"test"라는 자원은 단 하나만 유지하고, 레퍼런스 카운팅(Reference Counting)과 같은 기법으로 str1과 str2가 데이터를 공유하고 있다.  이 경우(COW)에는 true가 성립한다.


하지만 멀티 쓰레드라면 문제가 다르다.

str1을 한쪽 쓰레드에서 수정하고 str2에서 읽으려고 한다든가 동시에 접근이 발생했을때에 대한 처리가 내부적으로 동기화가 되어 있지 않다면 결과를 예상하기 힘들다.


COW 기법은 위 사항처럼 처음 의도 만큼 좋은 성능을 내지 못한다.

근래에는 많이 없어졌지만 아직도 사용되는 라이브러리들이 있으니, 세부 스펙을 자세히 살펴보고 사용 할 필요가 있다.



※ 얕은 복사(shallow copy) : 메모리 포인터만 복사

깊은 복사(deep copy) : 실제 데이터 전체를 복사

profile