2017-04-03 96 views
2

我有一段代碼,其讀取由線文件線,然後將其存儲兩個相應的二進制表示中的兩個向量。但矢量的大小和處理的總行數是零。OpenMP的文件中讀取在C++

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

沒有「共享」條款照顧?我應該使用'#pragma omp critical'作爲更新'p1','p2'和'c'的塊嗎? – viz12

+2

不,「共享」只是明確指出一個變量在線程之間共享。同步必須由用戶來處理。是的,你必須使用一個關鍵部分,但這會殺死你期望得到的所有加速。 –

回答

2

先讀取所有輸入,然後對其進行並行處理。

我不知道是否與fgets()是線程安全的,但是:

  • 如果是的話,你不會得到它並行多少好處。這是因爲,以保證沒有其他線程更新它需要阻塞的(除非它使用非阻塞的方式,但我認爲它不應該是這裏的情況)
  • 否則的話,你可能最終讀取多個倍相同的數據,甚至損壞的數據。

你有被分裂的文件,處理這些另一種選擇。無論如何,如果文件不是太大,請嘗試讀取所有文件並進行處理。如果它太大,請嘗試加載一些記錄(比如兩千行)並行處理,重複。您可能需要進行一些測試,以瞭解哪種方法更適合您。

〜 編輯:正如其他人說,你可能要檢查到這些變量的併發訪問過。把它放在一起,也許減少計算最終結果?請參閱: 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