2012-05-13 2 views
4

STL 벡터를 반복하고 값을 읽는 중입니다. 이 벡터를 변경할 수있는 또 다른 스레드가 있습니다. 이제 다른 스레드가 벡터에서 요소를 삽입하거나 제거하고 요소를 제거하면 반복기가 무효화됩니다. 관련된 자물쇠는 사용하지 않습니다. 내가 이터레이터 (접근법 2) 대신 인덱스 (접근법 1)를 통해 컨테이너에 액세스하면 스레드를 안전하게 만들 수 있습니까? 실적은 어떻습니까?C++ STL 벡터 반복자와 인덱스 액세스 및 스레드 안전성

struct A{int i; int j;}; 

접근법 1 :

size_t s = v.size();//v contains pointers to objects of type A 
    for(size_t i = 0; i < s; ++i) 
    { 
     A* ptr = v[i]; 
     ptr->i++; 
    } 

접근법 2 :

std::vector<A*>::iterator begin = v.begin(); 
std::vector<A*>::iterator end = v.end(); 
for(std::vector<A*>::iterator it = begin; it != end; ++it) 
{ 
    A* ptr = *it; 
    ptr->i++: 
} 

답변

3

OP "이터레이터 (접근법 2) 대신 인덱스를 통해 컨테이너에 액세스하면 (접근식 1) 스레드를 안전하게 만들 수 있습니까?

아니요, 데이터 구조에 대한 쓰기를 시작하면 어느 방법도 스레드로부터 안전하지 않습니다.

따라서 데이터 구조에 대한 액세스를 serialize해야합니다.

많은 시간과 좌절감을 줄이기 위해 미리 준비된 솔루션이 많이 있습니다. 예 :

스레드 안전 컨테이너 (예 : concurrent_vector)와 함께 제공되는 인텔 스레딩 구성 요소 (TBB).인덱스에 의해

  • 랜덤 액세스 :

    http://threadingbuildingblocks.org/

    concurrent_vector는 다음과 같은 기능을 가진 컨테이너입니다. 첫 번째 요소의 인덱스는 0입니다.

  • 여러 스레드가 컨테이너를 확장하고 동시에 새 요소를 추가 할 수 있습니다. 기존의 반복자 또는 인덱스를 무효화하지 않는 용기를 성장
  • . *

OP "무엇 성능에 대한?"

알 수 없음. 다른 컴파일러를 사용하는 다른 시스템에서 성능은 다르지만 선택 사항에 영향을 줄만큼 크지는 않습니다.

3

번호 STL 컨테이너 스레드 안전하지 않는다.

벡터에 액세스하는 동안 각 스레드 (제거하는 스레드/제거하는 스레드)에 독점적 액세스 권한을 제공해야합니다. 인덱스를 사용하는 경우에도 i 번째 엘레멘트를 제거하여 검색 한 포인터를 유효하지 않게 만들 수 있습니다. 표준 라이브러리 컨테이너

+0

+1 C/C++ 독립 라이브러리의 아무 것도 스레드로부터 안전하지 않은 것으로 간주됩니다. 그러나 POSIX 정의 함수는 thread-safe로 정의됩니다. – sj755

+4

@ seljuq70 : 진술이 잘못되었습니다. 가장 최근의 stnadards 업데이트가 발표되기 전에 사실 이었지만 C 및 C++ 모두 특정 스레드 안전 보장을 제공합니다. 그것들은 여러분이 원했던 것이 아닐지도 모르지만 라이브러리 구조가 쓰레드에 안전하지 않다는 것을 의미하지는 않습니다. 다양한 클래스는 실제로 많은 사람들이 스레드로부터 안전하다고 잘못 해석 한 것처럼 보이는 모니터가 없습니다 (대부분의 경우). –

+0

@ DietmarKühl 내 노트를보고 나면, 네가 절대적으로 옳은 것처럼 보인다. 거의 모든 시스템 및 라이브러리 함수는 스레드로부터 안전합니다. 또한 모든 POSIX 함수가 스레드로부터 안전하다는 점에 틀 렸습니다. 예를 들어, readdir과 strerror는 thread-safe로 정의되지 않습니다. – sj755

4

스레드 안전 보장은 매우 정직하고 (이 규칙은 ++ 2011하지만, 기본적으로 현재의 모든 라이브러리 구현이 해당 제한을 이러한 요구 사항을 준수하고 부과 C에 추가 된)됩니다

  1. 그것입니다 용기를 수정 한 스레드가
  2. 요구 컨테이너 객체 단위이다 (읽기 또는 쓰기)을 액세스하는 다른 스레드가 없다있을 경우 동시에 여러 독자
  3. 를 가질 OK

효과적으로, 이는 여러 스레드에서 액세스 한 컨테이너가 올바르게 처리되도록하기 위해 컨테이너 외부의 일부 메커니즘을 사용해야 함을 의미합니다. 예를 들어 뮤텍스 또는 리더기 잠금을 사용할 수 있습니다. 물론 대부분의 시간 컨테이너는 하나의 스레드에서만 액세스되며 모든 잠금 기능없이 잘 작동합니다.

Explict 잠금을 사용하지 않으면 인덱스 또는 반복기 사용 여부와 관계없이 데이터 경쟁이 발생하고 동작이 정의되지 않습니다.

+0

Approach1 대 Approach2의 성능에 대해 의견을 말씀해 주시겠습니까? – sank

+1

어느 것이 더 빠릅니까? 그들 중 하나. 플랫폼, 컴파일러, 컴파일러 버전, 컴파일러 플래그, 그리고 아마도 달의 위상에 따라 달라질 것입니다. 프로필을 작성해야합니다. 인덱스를 사용하는 선택자와 반복자를 사용하는 선택은 액세스되는 객체의 지역성에 비해 아마도 중요하지 않다는 점에 유의할 필요가 있습니다. –

0

알고리즘이 고정 크기 배열로 작동 할 수 있습니까?

이유 논리적으로 스레드 안전하고 잠금이없는 방식으로 (대부분의 종류의) 컨테이너를 수정하는 유일한 방법은 논리적으로 컨테이너 자체를 불변으로 만드는 것입니다. 즉, CONTAINER는 스레드 내에서 변경되지 않으며, 스레드 내의 요소 만 변경됩니다. 열차에서 박스 카의 내부와 어지러운 사이의 차이점을 생각해보십시오. 실제로는 트랙을 따라 내려가는 열차의 전체 상자 카를 제거하여 &을 추가하는 것과 비교하십시오. 요소에 간섭하는 것조차도 해당 데이터에 대한 조작이 특정 제한 조건을 준수하는 경우에만 안전합니다.

좋은 소식은 잠금 장치가 항상 세계의 끝이 아니라는 것입니다. 어쨌든 여러 실행 컨텍스트 (스레드, 프로그램 등)가 동일한 개체에 동시에 충돌 할 수있는 경우가 많습니다.