2013-04-23 85 views
6

我試圖並行在下面的函數循環使用OpenMPOpenMP的減少與重載運營商

void CEnergymulti::forcetwobody(vector<CMolecule*> m_mols,CPnt force0,CPnt torque0) 
{ 
const int nmol=m_mols.size(); 
vector<CMolecule*> twomols(2); 
CPnt forcetemp,torquetemp; 
twomols.clear(); 
force0.zero(); 
torque0.zero(); 
forcetemp.zero(); 
torquetemp.zero(); 
#pragma omp parallel for reduction(+:force0,torque0) private(twomols) 
for(int j=1;j<nmol;j++) 
     { twomols.push_back(m_mols[0]); 
     twomols.push_back(m_mols[j]); 
     CMolecule::polarize_mutual(twomols,false, 1000); 
     twomols[0]->computeMol_Force_and_Torque(forcetemp,torquetemp); 
     force0+=forcetemp; 
     torque0+=torquetemp; 
     forcetemp.zero(); 
     torquetemp.zero(); 
     twomols.clear(); 
     } 
    REAL converter=COUL_K*IKbT; 
    force0*=converter; 
    torque0*=converter; 
    return; 
    } 

當我編譯的代碼,它提供了以下消息:

EnergyD_multi.cpp: In static member function ‘static void 
CEnergymulti::forcetwobody(std::vector<CMolecule*, 
std::allocator<CMolecule*> >, CPnt, CPnt)’: EnergyD_multi.cpp:226: 
error: ‘torque0’ has invalid type for ‘reduction’ 
EnergyD_multi.cpp:226: error: ‘force0’ has invalid type for 
‘reduction’ 

我明白變量'force0'和'torque0'既不是雙重數據也不是整型數據,而是'CPnt'類型,這是一種定義爲表示空間中三維向量的類。對於'CPnt'類,運算符'+'和' - '已經由運算符重載定義。所以我的問題是:在OpenMP中的減少不能處理這樣的重載操作符嗎?有沒有其他方法可以將這個循環與OpenMP並行化,而不需要減少'force0'和'torque0'的每個組件?

非常感謝。

+0

您是否得到了應有的工作?我更改了代碼以使用OpenMP執行過載操作。讓我知道它是否有效。如果有錯誤,請參閱鏈接以瞭解主要思想。 – 2013-04-25 19:32:24

+0

非常感謝@raxman。使用並行化方案,您建議可以編譯代碼。不過,我仍然對與'nowait'的循環並行化有點困惑。這是因爲我仍然認爲對於每個線程來說,循環'twomols'和'forcetemp'中的變量應該被視爲'私人',但是您沒有將它們列爲私人。 – user2226358 2013-04-26 06:35:55

+0

「#pragma omp parallel」中的所有內容都是私人定義的。只有force0和torque0是共享的,因爲它們不在omp pragma – 2013-04-26 06:40:14

回答

7

的確,OpenMP減少無法處理這樣的重載操作符。但是,還有一個選擇。重寫OpenMP減少的一種方法是使用nowaitatomic參數。 http://bisqwit.iki.fi/story/howto/openmp/#ReductionClause 。這與正常方式一樣快。

如果將atomic替換爲critical,則可以使用更復雜的重載操作符。這並不像使用atomic那麼快,但它仍然適用於我的經驗。

我這樣做,所以我可以使用運算符一次操作4或8浮動(與SEE或AVX)。 reduction with OpenMP with SSE/AVX

編輯:我改變了你的代碼,以反映我認爲會做你想做的事。

void CEnergymulti::forcetwobody(vector<CMolecule*> m_mols,CPnt force0,CPnt torque0) 
{ 
    const int nmol=m_mols.size(); 
    force0.zero(); 
    torque0.zero(); 
    #pragma omp parallel 
    { 
     CPnt force0_private; 
     CPnt torque0_private; 
     force0_private.clear(); 
     torque0_private.clear(); 
     #pragma omp for nowait 
     for(int j=1;j<nmol;j++) 
     { 
      CPnt forcetemp,torquetemp; 
      forcetemp.zero(); 
      torquetemp.zero(); 
      vector<CMolecule*> twomols(2); 
      twomols.clear(); 
      twomols.push_back(m_mols[0]); 
      twomols.push_back(m_mols[j]); 
      CMolecule::polarize_mutual(twomols,false, 1000); 
      twomols[0]->computeMol_Force_and_Torque(forcetemp,torquetemp); 
      force0_private+=forcetemp; 
      torque0_private+=torquetemp; 
     } 
     #pragma omp critical 
     { 
      force0 += force0_private; 
      torque0 += torque0_private; 
     } 

    } 
    REAL converter=COUL_K*IKbT; 
    force0*=converter; 
    torque0*=converter; 
    return; 
} 
+0

我認爲第二個編譯指示(即'#pragma omp parallel for nowait')應該是'#pragma omp for nowait',即沒有並行(並行結構已經在其外部設置)。我的編譯器抱怨說,你不能在parallel中加入nowait,因爲在parallel的後面應該有一個隱含的障礙。似乎nowait和parallel是矛盾的指令。 – 2013-08-22 23:02:46

+0

@VarunGulshan,你是對的,它應該是'#pragma omp for nowait'。我只是修復它。 – 2014-08-04 07:32:53

+0

Arent你失去這樣的對數複雜性? --- 最糟糕的情況是每個線程都等待進入關鍵部分,然後他們會連續添加結果。 --- 所以最後你有'O(nmol/thread_num)+ O(thread_num)'而不是'O(nmol/thread_num)+ O(log(thread_num))' --- 這可能會使強大的電腦(即超級計算機) – Jan 2017-02-17 07:05:32