2010-12-10 1 views
4

체크 된 STL implentation을 사용하여 코드에 예기치 않은 어설 션 faillures가 있습니다.C + + 벡터, 다른 스레드에서 push_back이 충돌하고 있습니까?

약간의 연구 끝에 나는 벡터가 생성 된 스레드와 다른 스레드에서 호출 된 벡터에서 push_back으로 문제를 좁혔다. 이 문제를 재현하는

간단한 코드는 다음과 같습니다

class SomeClass 
    { 
    private: 
     std::vector<int> theVector; 
    public: 
     SomeClass() 
     { 
      theVector.push_back(1); // Ok 
     } 


     void add() 
    { 
      theVector.push_back(1); // Crash 
    } 
}; 

유일한 차이점은 SomeClass 내 메인 스레드에서 통해 인스턴스 것을, 그리고 다른 스레드에서 호출됩니다 추가 할 수 있습니다. 그러나 아무런 통일성 문제가 없습니다. 가장 간단한 형태의 코드는 위에서 언급 한 경우를 제외하고는이 벡터에서 읽거나 쓰는 것이 아닙니다.

push_back 코드를 살펴보면 count() 또는 size()와 같은 std :: vector의 일부 메서드가 다른 thred (메서드 "add")에서 호출 될 때 가비지를 반환하고 호출 할 때 올바른 값을 발견했습니다. (예를 들어, 생성자에서) 생성 스레드에서

다중 스레드 환경에서 std :: vector를 사용할 수 없다고 결론 내리겠습니까? 아니면이 문제에 대한 해결책이 있습니까?

편집 : 휘발성 제거

편집 2 : 당신이 문제가 멀티 스레드에 거짓말을하지 않는 것이 가능하다고 생각합니까? 내 테스트 실행에서 add는 한 번만 호출됩니다 (중단 점을 사용하여 확인 됨). 생성자에서 push_back을 제거하면 충돌이 발생합니다. 그래서 결국, 벡터의 메서드를 한 번만 호출하더라도 한 번 호출 된 함수에서 어설 션을 실패하게 만듭니다. 그러므로 concurency가있을 수 없다, 또는 ...?

+2

실제로 동시성 벡터가 작동해야하는 경우가 있습니다. 벡터 *로 작업하는 스레드가 두 개 이상인 경우 * 병렬 *로 작동하지 않습니다. – Drakosha

+1

각 스레드마다 자체 힙이있는 환경에 있습니까? – JimR

+0

'예약'이라고 해보십시오. – Fozi

답변

2

push_back을 호출 할 때 아무도 벡터에 쓰거나 벡터에서 읽지 않는다고 보장 할 수 있으면 실패하지 않아도됩니다. 높은 수준의 메모리 손상을 처리 할 수 ​​있습니다. "This"가 SomeClass의 실제 인스턴스를 가리키고 다른 멤버를 확인하는지 확인해야합니다.

+0

+1'SomeClass' 인스턴스를 검사합니다. –

+0

여러분은 정말로 옳습니다 : 문제는 vactor 나 스레드가 아니라 SomeClass 인스턴스입니다. 아이디어에 감사드립니다. – Dinaiz

1

표준 라이브러리가 다중 스레드를 지원하는지 여부는 구현이 정의하는지 여부. 특정 컴파일러에 대한 설명서를 읽어야합니다.

는 Additionaly 당신이 할 수있는 일은 다음 코드와 같이 일부 로그 메시지를 추가하는 것입니다

class SomeClass 
    { 
    private: 
     volatile std::vector<int> theVector; 
    public: 
     SomeClass() 
     { 
      std::cout << "SomeClass::SomeClass" << std::endl; 
      theVector.push_back(1); // Ok 
     } 
     ~SomeClass() 
     { 
      std::cout << "SomeClass::~SomeClass" << std::endl; 
     } 
     void add() 
     { 
      std::cout << "SomeClass::add" << std::endl; 
      theVector.push_back(1); 
     } 
}; 

하면 SomeClass의 인스턴스가 여전히 당신이 add 함수를 호출 할 때 존재하는지 확인합니다.

1

대부분의 STL 구현은 스레드로부터 안전하지 않습니다. 벡터에 액세스하는 동안 두 스레드가 서로 쾅쾅 거리지 않도록 스레드 동기화 (예 : 뮤텍스)를 사용해야합니다. 기본적으로해야 할 일은 벡터와 뮤텍스 및 읽기 및 쓰기 작업을위한 벡터를 보호하는 접근 자 함수를 포함하는 클래스를 만드는 것입니다.

+0

@Gene : 사람들이 "스레드 안전"이라고 말하면 "특별한 일을하지 않고도 스레드에서 사용할 수 있습니다"라고 생각합니다. –

+0

이 답변에는 @pts '와 같은 오류가 있습니다. 뮤텍스와 동기화는 여기서 전혀 관련이 없습니다. –

+0

@ 존 : 진의 정의는 다른 어떤 것과 마찬가지로 좋습니다. "스레드 안전성"은 아무도 그 의미에 동의하지 않기 때문에 가치없는 자격입니다. –

7

std::vector은 다중 스레드 환경에서 사용할 수 있습니다. 단, 두 스레드의 벡터에 한 번에 액세스 할 수는 없습니다. 나는 항상 문제없이 그것을한다.

vector은 문제가 아니기 때문에 동기화 메커니즘을 자세히 살펴 봐야합니다. 가장 가능성있는 문제 일 수 있습니다.

vectorvolatile으로 표시 한 것으로 나타났습니다. 당신은 그것이 volatile이 동기화를 제공 할 것이라고 기대합니까? 왜냐하면 그렇게하지 않을거야. See here for more information.

EDIT : 원래 잘못된 링크가 제공되었습니다. 이 문제가 해결되었습니다. 혼란을 드려 죄송합니다.

+0

휘발성이 잘못되어 언급 한대로 컴파일되지 않습니다. D – Dinaiz