2017-04-03 3 views
2

파일을 한 줄씩 읽은 다음 두 벡터에 두 개의 해당 이진 표현을 저장하는 코드 조각이 있습니다. 그러나 벡터의 크기와 처리 된 총 라인 수는 0입니다.C에서 OpenMP 파일 읽기

int numLines = 319426908; // calculated before for loop 
    char temp[100]; 
    vector<long long int> p1, p2; 
    long long int c = 0; 

    #pragma omp parallel for schedule(dynamic) shared(c, p1, p2, fp) private(temp) 
     for(int i=0; i<numLines; i++){ 
     if(fgets(temp, 100, fp) != NULL){ 
      temp[strlen(temp)-1] = '\0'; 
      long long int *A = toLongLong(temp); 
      p1.push_back(A[0]); 
      p2.push_back(A[1]); 
      c++; 
     } 
     } 
     cout << "Completed ...c = " << c << endl; 
     cout << "p1.size: " << p1.size() << " p2.size: " << p2.size() << endl; 

이 출력

Completed ...c = 0 
p1.size: 0 p2.size: 0 

가 어디 위의 코드 조각에 잘못 가고있다?

+2

경쟁 조건이 있습니다. 'push_back' 연산과'C++'('++ c'가되어야 함)는 매우 중요하며 중요한 부분으로 들어가야합니다. 그러나 파일을 병렬로 읽는 것은 보통 좋은 생각이 아닙니다. [HDF5] (https://en.wikipedia.org/wiki/Hierarchical_Data_Format)와 같이 병렬로 작성하고 읽도록 설계된 파일 형식이 있습니다. –

+0

'shared' 절이 그것을 처리하지 않습니까? 'p1','p2','c'를 갱신하고있는 블록에'#pragma omp critical '을 사용해야합니까? – viz12

+2

아니요, '공유'는 변수가 스레드간에 공유된다는 것을 명시 적으로 나타냅니다. 동기화는 사용자가 처리해야합니다. 그렇습니다. 중요한 섹션을 사용해야하지만, 예상되는 모든 속도가 빠져 나갈 것입니다. –

답변

2

먼저 모든 입력을 읽은 다음 그 처리를 병렬 처리하십시오.

내가는 fgets()는 스레드 안전한지 모르겠지만, :이 경우

  • 는, 당신은 못해 병렬화에 많은 혜택을받을. 다른 스레드가 그것을 업데이트하는 것을 보장하는 데 필요한 블로킹 때문입니다 (비 블로킹 접근법을 사용하지 않는 한, 여기에 해당해서는 안됩니다).
  • 그렇지 않으면 여러 번 읽을 수 있습니다. 동일한 데이터 또는 심지어 손상된 데이터.

또 다른 옵션은 파일을 분할하여 처리하는 것입니다. 어쨌든, 파일이 너무 크지 않다면 모든 것을 읽은 다음 처리하십시오. 크기가 너무 크면 병렬로 처리하는 몇 가지 레코드 (2 천 라인)를 반복하여 반복 해보십시오. 어떤 접근 방법이 더 적합한 지 알기 위해 몇 가지 테스트를해야 할 수도 있습니다.

~ 편집 : 다른 사람들이 말했듯이 이러한 변수에 대한 동시 액세스를 확인할 수도 있습니다. 모든 것을 합치려면 최종 결과를 계산하는 데 줄여야할까요? 참조 : C++ OpenMP Parallel For Loop - Alternatives to std::vector

2

MateusMP의 답변에 명시적인 예를 추가하려면 C++ 표준 라이브러리를 더 많이 사용하도록 코드를 리팩터링해야합니다. 많은 기능과 데이터 구조가있어보다 쉽게 ​​읽고 코드를 읽을 수 있습니다.

#include <array> 
#include <fstream> 
#include <string> 
#include <vector> 

std::array<long long,2> toLongLong(std::string); 

int main() 
{ 
    int c = 0; 
    std::vector<long long> p1; 
    std::vector<long long> p2; 

    int n_lines = 10; 
    std::vector<std::string> lines(n_lines); 

    // Read the file 
    std::ifstream file("test.txt" , std::ios::in); 
    for (int i = 0; i < n_lines; ++i) 
    std::getline(file, lines[i]); 
    file.close(); 

    // Process the contents in parallel 
    #pragma omp parallel 
    { 
    int c_local = 0; 
    std::vector<long long> p1_local; 
    std::vector<long long> p2_local; 

    #pragma omp for 
    for (int i = 0; i < n_lines; ++i) 
    { 
     std::array<long long,2> A = toLongLong(lines[i]); 
     p1_local.push_back(A[0]); 
     p2_local.push_back(A[1]); 
     ++c_local; 
    } 

    #pragma omp critical 
    { 
     p1.insert(p1.end(), p1_local.begin(), p1_local.end()); 
     p2.insert(p2.end(), p2_local.begin(), p2_local.end()); 
     c += c_local; 
    } 
    } 
} 

toLongLong이 구현되어 있지 않으므로 컴파일되지만 연결되지 않습니다.

+0

예, 이것은 안전한 접근이지만 메모리에 줄을 저장하고 싶지 않습니다. – viz12