http://www.gpgstudy.com/forum/viewtopic.php?p=120514





올리기std::vector size()함수 쓰레드동기화안해줘도되죠?2009-06-15 02:11
 

size()얻는함수쓸때 크리티컬섹션안잡아줘도 되죠?





답:



안녕하세요. 매크로 없는 메비~랍니다. 

최종적으론 '해줘야 합니다'가 답입니다. 최종적이란 뜻은 size() 에만 걸어주는건 의미가 없고 size() 와 그것을 사용하는 모든 다른 작업들이 하나의 락에 포함되어야 하기 때문입니다. 

첫번째로 size() 를 호출하는 것은 vector 의 현재 크기를 얻어오기 위한 것인데 이 함수가 Thread-Safe 하다는 것이 보장되어야 합니다. STL의 종류에 따라 다르지만 일단 VC++에 포함된 STL 을 기준으로 보자면 이 함수는 Thread-Safe 하지 않습니다. 

코드:
/* VS2008 SP1 <vector> 파일에서 복사해옴 */
 
size_type size() const
    {   // return length of sequence
    return (_Mylast - _Myfirst);
    }


함수는 아주 간단하지만 명령은 일단 (1) _Mylast 를 CPU 레지스터에 읽어온다음 (2) _Myfirst 값을 빼준다~ 라는 최소한 두가지 명령으로 이루어져 있습니다. 그렇지만 (1) 작업이 완료된 순간 쓰레드 스위칭이 일어나고 다른 쓰레드에서 vector:push_back() 를 호출해서 재할당이 일어나게 되면 그 순간 다른 쓰레드에서 size() 계산을 위해서 레지스터에 올라간 _Mylast 의 주소는 이미 무효화된 메모리 주소를 가르키고 있는 상태가 됩니다. 이런 작업이 일어난다음 기존 쓰레드가 다시 시작되어 (2) 작업이 진행되면 vector::size() 함수는 잘못된 값을 리턴하게 됩니다. 경우에 따라 계산결과가 음수가 나와 size_t 로 타잎이 결정되어 매우 큰 크기가 리턴될 수도 있습니다. 

두번째가 좀더 심각한데 vector::size()가 온전하게 작동한다 하더라도 그 값이 리턴된 시점부터 이 size() 값이 유효하다는 보장을 받을 수 없다는 점 입니다. 위의 size() 함수 사이에 쓰레드 변환이 일어나서 내부 값들이 바뀌었듯이 size()가 호출하여 계산이 끝나 직후부터 그 값을 다시 사용할 시점 사이에 size() 는 언제나 바뀔 수 있습니다. size() 가 값을 계산한 이후부터 그것을 사용할때까지 vector 가 변경되지 않는다는 보장이 없다는 뜻입니다. 

물론 size() 의 값을 간단한 디버깅 출력용이나 유효성 검사등의 용도로 쓴다면 이러한 결함이 용납될 수 있습니다. 그렇지만 그 값이 vector 에 루프를 돌기 위한 값이거나 또는 특정 계산을 하기 위해 미리 vector 의 크기를 재는 용도라면 size() 이후부터 size()의 결과물을 다 사용하는 끝날때까지 vector를 다른 쓰레드가 접근하지 못하도록 확실히 막아줘야 합니다.



반응형

+ Recent posts