2017-05-01 1 views
2

내가 삽입하려고하는 for 루프의 OpenMP를 사용하려고위한 OpenMP의 내부 해시 맵/해시 맵 (std::unordered_map)업데이트 루프

해시 맵을 업데이트하고 키는 실제로 클래스의 구성원 그래서 나는 그들의 주소를 나타내는 포인터를 할당했다. 키는 또한 전역 함수에 의해 반환 된 해시 값이다.

다음은이 작업을 수행하는 가장 쉬운 방법 인 것처럼 보이지만 해시 맵이 올바르게 업데이트되지 않습니다. 무언가가 잘못되었지만 해결 방법을 모르겠습니다. 미리 감사드립니다.

void MyClass::ProcessBuffer(void) 
{ 
    omp_set_num_threads(4); 
    std::unordered_map<unsigned long long,unsigned int>* hashptr=&m_sequencehash; 
    std::vector<std::string>* bufferptr=&m_buffer; 
    unsigned int sizevec=m_kmer_size; 
    size_t i; 
    #pragma omp parallel for 
    for (i=0; i<READSTR_BUF_SIZE;++i) 
    { 
     ++(*hashptr)[_hash((*bufferptr)[i],sizevec)]; 
    } 

} 
+3

'std :: unordered_map'은 스레드로부터 안전하지 않으므로 코드에 경쟁 조건이있어 정의되지 않은 동작이 발생합니다. –

+0

아마 [해시 맵에 데이터를 병렬로 추가하기] (http://stackoverflow.com/questions/10064372/adding-data-to-a-hashmap-in-parallel) – Arash

+0

병렬 처리에서 얻을 수있는 성능 향상에 대해 궁금한 점이 있습니다. 궁극적으로는 스레드 안전을 위해 잠금을 필요로하는 작업입니까? –

답변

1

이 문제를 해결하는 가장 쉬운 방법은 각 스레드에 대한 새 맵을 만든 다음이를 단일 맵으로 순차적으로 줄이는 것입니다. 이것은 고전적인 map-reduce 시나리오입니다.

int s = omp_get_num_threads(); 
std::unordered_map<unsigned long long,unsigned int> res[s]; 

// Map step 
#pragma omp parallel for 
for (i=0; i<READSTR_BUF_SIZE;++i) 
{ 
    int t = omp_get_thread_num(); 
    res[t][_hash((*bufferptr)[i],sizevec)]++; 
} 

// Reduce step 
for (int i=0; i < s; i++) { 
    for (auto r : res[s]) { 
     (*hashptr)[r.first] += r.second; 
    } 
} 

감소를 동시에 수행하면 위험한 것일 수 있습니다. 그래도 같은지도에 동시에 액세스해야하기 때문입니다. 지도의 구현을 모르는 경우이지도가 안전한지 알 수 없습니다.

또는 다른 해시 간격을 다른 버킷에 배치하여 서로 다른 맵간에 해시 값을 분할 할 수 있습니다. 이렇게하면 다른 스레드가 축소 단계에서 동일한 해시 값에 액세스하지 못하게됩니다. 그러나 작은 데이터 세트에서는 소수의 버킷으로 양호한 파티션 기능을 찾기가 어렵습니다. 버킷을 너무 많이 사용하면 일련 번호와 비교할 때 상당한 오버 헤드가 발생할 수 있습니다.

+0

대답은 올바른 방향입니다. 그러나 '평행선'에서'res' /'r'에 대한 정의는 잘못되었습니다. 또한 설명서 대신 적절한 축소를 사용해야합니다. [이 응답] (http://stackoverflow.com/a/43064331/620382)도 참조하십시오. – Zulan

+0

감사합니다. res에 대한 액세스를 수정했습니다. –

+0

적절한 축소 기능을 사용하면 같은지도에 동시에 액세스해야하기 때문에 위험합니다. 지도의 구현을 알지 못해서 안전하다고 확신 할 수 없습니다. –