2010-12-03 12 views
11

N 요소의 벡터가 있지만이 벡터의 n 요소까지 의미있는 데이터가 있다고 가정 해 보겠습니다. 하나의 업데이터 스레드는 n 번째 또는 n + 1 번째 요소를 업데이트하고 (n = n + 1로 설정), n이 N에 너무 가깝고 필요한 경우 vector :: resize (N + M)을 호출합니다. 업데이트 후에는 스레드가 여러 하위 스레드를 호출하여 최대 n 번째 데이터를 읽고 일부 계산을 수행합니다.STL 벡터 및 스레드 안전

자식 스레드는 결코 데이터를 변경하거나 삭제하지 않으며 (실제로 데이터는 삭제되지 않습니다) 업데이트 프로그램은 업데이트 완료 직후에 자식을 호출합니다.

지금까지 아무런 문제가 발생하지 않았지만 이전 업데이트에서 일부 하위 작업 스레드가 남아있는 경우 큰 메모리 블록에 벡터를 재 할당하는 동안 문제가 발생할 수 있는지 묻고 싶습니다.
또는 다중 스레드 된 경우 벡터가 스레드로부터 안전하지 않으므로 안전합니까?

편집 : 업데이터가 vector :: resize (N + M, 0)을 호출 할 때 삽입이 이루어 지므로 내 문제의 가능한 해결책이 있습니까? STL 벡터의 뛰어난 성능으로 인해 잠금 가능 벡터로 대체하려고하지 않거나이 경우 성능이 뛰어나고 알려진 잠금없는 벡터가 있습니까?

답변

19

이전 업데이트에서 일부 하위 작업 스레드가 남아있는 경우 큰 메모리 블록에 벡터를 재 할당하는 동안 문제가 발생할 수 있는지 묻고 싶습니다.

예, 이것은 매우 나쁩니다.

여러 스레드의 컨테이너를 사용 중이고 하나 이상의 스레드가 컨테이너의 상태를 수정할 수있는 일부 작업을 수행 할 수있는 경우 컨테이너에 대한 액세스를 동기화해야합니다. (특히, 삽입 및 소거)을 재 할당이 필요하지 않은 경우에도, 그 상태를 변경하는 크기를 변화 std::vector 경우, 아무것도

(모든 삽입 또는 삭제가 std::vector의 내부 크기 부기 데이터가 갱신 될 필요) . 문제에 대한


하나 개의 솔루션은 생산자가 동적으로 std::vector를 할당하고 그것을 소유 할 std::shared_ptr<std::vector<T> >를 사용하여 소비자의 각이 std::shared_ptr를 제공해야하는 것입니다.

생산자는 더 많은 데이터를 추가 할 필요가

, 동적으로 이전 std::vector에서 새로운, 더 큰 크기와 요소의 사본을 새로운 std::vector를 할당 할 수 있습니다. 그런 다음 새로운 소비자를 분사하거나 새로운 데이터로 소비자를 업데이트 할 때 새로운 std::vectorstd::shared_ptr을 입력하기 만하면됩니다.

+0

@James McNellis : 예. 좋은 충고입니다.나는 직접 재배치를 할 수있다. 사실 벡터는 벡터에 대한 포인터를 보유하는 클래스 내에 래핑됩니다. 그것은 shared_ptr이 아니지만 새로운 큰 벡터를 쉽게 만들 수 있으며 이전 요소의 요소를 복사하고 삭제할 수 있습니다. 따라서 대용량 메모리 블록을 복사하는 가장 빠른 방법은 무엇입니까? CopyMemory()? –

+1

더 간단한 해결책은 벡터 대신에'std :: deque'를 사용하는 것이 아닌가? 따라서 벡터와 거의 동등한 성능을 제공하면서도 재 할당을 완전히 피할 수 있습니다. – jalf

+0

@jalf : 재 할당 만이 유일한 걱정거리가 아니기 때문에 'std :: deque'를 사용하는 것이 안전하다고 생각하지 않습니다. 'std :: deque :: operator []'가 'deque'내부 또는 다른 부기의 크기를 검사하지 않는다는 보장이 없으므로 소비자가'operator []를 호출하는 경쟁 조건이 발생할 수 있습니다. '는 생산자가 내부 상태를 수정하는 데이터를 추가하는 동안 내부 상태를 읽는다. –

1

작업자가 데이터 스레드 안전 작업을 어떻게 결정합니까? 작업자와 제작자간에 신호가 전달 되었습니까? 그렇지 않다면 생산자가 여전히 작업중 인 동안 벡터가 움직일 수있는 문제가 분명합니다. 대신 std::deque으로 이동하면이 문제를 해결할 수 있지만 (std::dequepush_back의 이터레이터를 무효화하지만 요소에 대한 참조는 영향을받지 않습니다).

+0

@stonemetal : 근로자와 생산자간에 신호가 없습니다. 나는 어떻게 deque를 사용할 것인가? –

+0

@stonemetal : push_back()을 사용하여 데이터를 삽입하지 않습니다. 크기를 조정 한 다음'vec [n] = X;를 호출합니다.이 점이 중요합니까? –

+0

그것은 당신이 어떻게 일을 노동자들에게 나누어 주느냐에 달려 있습니다. 끝까지 추가 만한다고 말하면, push_back을 사용하거나 필요에 따라 크기를 조정 한 다음, 프론트를 밀거나 팝하지 않고 절대로 변경하지 않는 인덱스로 작업자에게 작업을 넘길 수 있으며, 작업을 배포 할 수도 있습니다 요소가 연속적으로 보장되지는 않지만 요소가 이동하지 않도록 보장되므로 포인터 블록으로 배열 스타일 시작 및 길이 설정보다는 작업자가 필요로하는 각 요소에 대한 포인터가 필요합니다. 반복기는 크기 조정시 유효하지 않으므로 옵션이 아닙니다. – stonemetal