2010-08-10 9 views
5

벡터에 값을 추가하고 방금 추가 한 값의 인덱스를 반환하는 함수를 만들어야합니다.Atomically std :: vector :: push_back() and return index

예 :

int append(std::vector<int>& numbers, int number){ 
    int retval = numbers.size(); 
    // what if some other thread calls push_back(number) in between these calls? 
    numbers.push_back(number); 
    return retval; 
} 

반환 된 인덱스가 벡터 값을 추가 여러 스레드가있을 수 있습니다 경우에도 항상 올 수 있도록 내가 원자 적으로이 일을하고 싶습니다. push_back이 방금 추가 한 항목의 색인을 반환하면 쉽습니다. 올바른 색인이 리턴됨을 어떻게 보장 할 수 있습니까?

+5

사실 push_back() 자체가 스레드로부터 안전하지 않으므로 push_back()이 인덱스를 반환하면 쉽지 않을 것입니다. –

+0

모든 동시 쓰기에 대해 컨테이너를 보호해야합니다. 동시 일반 push_back()에는 이미 벡터 외부 동기화가 필요합니다. –

+3

많은 실제 응용 프로그램에서 작은 스레드 안전 작업을 만드는 것이 올바른 해결책이 아니므로 더 큰 코드 묶음을 보호해야합니다.스레드 안전 컬렉션은 통신 메커니즘으로 사용하는 것이 좋습니다. 즉, 이것은 그러한 경우 일 수 있습니다. –

답변

11

std::vector에는 스레드가 내장되어 있지 않습니다. 당신은 그것을 확장 할 boost::mutex을 사용할 수

int append(std::vector<int>& numbers, int number){ 
    boost::mutex::scoped_lock slock(my_lock); 
    int retval = numbers.size(); 
    numbers.push_back(number); 
    return retval; 
} 

당신은 같은 방법으로 모든 읽기/쓰기 작업을 보호해야합니다. 또 다른 방법은 std::vector에 대한 래퍼 클래스를 만들어 스레드 지원으로 확장합니다. 자세한 내용은 this 질문을 확인하십시오.

+1

다른 스레드가이 함수를 호출하는 것 외의 다른 벡터로 어떤 일을 할 때 어떻게 작동합니까? numbers.clear()를 호출하는 다른 스레드는 여기 scoped_lock을 존중하지 않을 것입니다. –

+0

이 작업은 가능하지만이 작업 만 보안됩니다. 누구나 같은 객체에서 다른 곳의 'push_back()'을 수행하고 깨뜨릴 수 있습니다. – sharptooth

+4

읽기/쓰기 작업을 보호해야하는 경우가 하나 있습니다. OP가 스레드 지원으로 확장 할'std :: vector '에 대한 래퍼 클래스를 만들어야합니다. 자세한 내용은 [this] (http://stackoverflow.com/questions/1099513/threadsafe-vector-class-for-c) 질문을 확인하십시오. –

3

STL 컨테이너는 스레드 안전성이 없으므로 (push_back() 만 호출해도)이 문제를 직접 해결해야합니다. STL 외부에서 적절한 동기화 기본 요소를 사용해야합니다.

0

는 올바른 인덱스가 반환되는 것을 보장하기 위해 뮤텍스를 사용할 필요가

가장 강력한-보증 솔루션은 코드에서 모든 곳에서 모든 동작을 제어 의미 이러한 모든 작업에 대한 전체 벡터를 (잠그는 것입니다
+0

이것은 정말로 의견이며 질문에 대한 답변이 아닙니다. 작성자에 대한 의견을 남기려면 "의견 추가"를 사용하십시오. –

+2

동의하지 않습니다. 나는 이것이 대답이라고 생각한다. 받아 들여진 응답은 또한 동일한 통보를 그러나보기와 함께 준다. –

0

이것은 동기화 된 벡터를 만드는 것을 의미합니다).

그것은이 같은 간단한 당신을 위해 할 것입니다 수 있습니다 :

이 약
int append(std::vector<int>& numbers, int number){ 
    int retval = numbers.size(); 
    // what if some other thread calls push_back(number) in between these calls? 
    numbers.push_back(number); 
    int newSize = numbers.size(); 
    //this bit is as a short-cut in common, easy, cases 
    if(newSize = retval + 1) //no need for further complication 
    return retval; 
    while(++retval < newSize) 
    if(numbers[retval] == number) 
     return retval; 
    //If we get this far, numbers have been deleted, not added. More discussion below. 
} 

한 가지입니다 스레드가 밀어 경우 3, 3, 3, 3 다음 잘못된 것이다 반환 된 인덱스, 그것이 여전히 3에 대한 지표 일지라도 그것은 괜찮은지 아닌지는 당신의 목적에 달려 있습니다.

또 하나의 이유는 벡터가 터지거나 짧아지면 기껏해야 위의 코드에 주석을 달았을뿐입니다. 오류가 나빠질수록 (우리가 구한 후에 다시 튀어 나오기 때문에) newSize, [retval] 액세스가 무효화됩니다. 이 경우가 발생할 수 있는지 고려해야합니다 (코드의 나머지 부분에서 결코 알지 못할 수도 있음).

이 제한 사항이 사용 사례에 비해 너무 큰 경우 완전히 동기화 된 벡터를 만드는 것이 내가 두려워 할 수있는 최선이라고 생각합니다.

2

Visual Studio 2010에서는 concurrent_vector을 사용할 수 있으며 동기화 된 확장 기능을 제공합니다. This topic은 동시 컨테이너 각각을 나열합니다.

이들은 인텔 TBB에서도 동일한 구문 + 의미로 사용할 수 있으며 크로스 플랫폼에서 사용할 수 있습니다.

관련 문제