2015-11-26 24 views
1

我嘗試瞭解英特爾tbb中的任務。我試圖創建一個並行算法來解決兩個「塊」L(2,n)的拼音問題(https://en.wikipedia.org/wiki/Langford_pairingtbb-tasks不會收到給定的參數

我的算法在我調用順序時工作,但我想在任務中翻譯它。這是我的算法應該做的:

  • 使大小2 * N的向量,初始化爲「0」
  • 爲0,直到(1 +循環計數器+距離的塊)<大小的矢量做:
  • 重複給定的矢量
  • 加上循環計數器
  • 當前塊添加關於當前塊的1 +循環計數器+距離的塊
  • 如果這不是最後的塊:
  • 做同樣與塊區別任務-1和複製已經填補載體
  • 否則,檢查是否有「0」左
  • 如果不是,這是一個有效的解決方案

我目前忽略對稱

這是當前的代碼

int langford_task (int step, vector<int> v) 
{ 
task_group g; 
int counter = 0; 

cout << "current step: "<< step << endl; 
cout << "current vector in task: "; 

printVector(v); 

//'1+var+step' == 1 + our loopcounter + the distance of two 'blocks' 
for (unsigned int var = 0; 1+var+step < v.size(); ++var) 
{ 

    if (v[ var ] == 0 && v[ 1+var+step ] == 0) 
    { 
     vector<int> recV = v; 
     recV[var] = step; 

     recV[1+var+step] = step; 

     cout << "recV = "; 
     printVector(recV); 
     if (step - 1 != 0) 
     { 
      //make a task with step -1 and the new filled vector 
      g.run([&]{ counter += langford_task(step-1, recV); }); //spawn a task 
     } 
     else 
     { 
      // if there is no "0" in our vector, we found a valid solution and return 1 
      if(!(std::find(recV.begin(), recV.end(), 0) != recV.end())) 
       return 1; 
     } 
    } 

} 
g.wait(); //wait for tasks 

return counter; 
} 

從理論上講,task_group應在福爾循環結束等待,所以所有的子任務s可以先完成。

我打印載體,這樣我就可以看到裏面是什麼,並且那有點兒奇怪:

current step: 3 
current vector in task: [0, 0, 0, 0, 0, 0, ] 
recV = [3, 0, 0, 0, 3, 0, ] 
recV = [0, 3, 0, 0, 0, 3, ] 

一切正常,直到任務來

current step: 2 
current vector in task: [28848976, 0, 0, 0, 0, 3, ] 
recV = [28848976, 2, 0, 0, 2, 3, ] 
current step: 1 

這絕對是奇怪的。我不得不提到「28848976」似乎是一個隨機數字。它始終是不同的,大部分的

我預期的時間它的「0」:在「當前步驟:2」,「在工作電流矢量」 -section

[3, 0, 0, 0, 3, 0, ] 

,因爲這僅僅是參數我已經賦予這個功能。

它「工作」,當我添加 g.wait(); //等待任務

直屬

g.run(...) 

但是這會消耗更多的執行時間則沒有在所有的工作任務,並可能不再平行。

current step: 3 
current vector in task: [0, 0, 0, 0, 0, 0, ] 
recV = [3, 0, 0, 0, 3, 0, ] 
current step: 2 
current vector in task: [3, 0, 0, 0, 3, 0, ] 
recV = [3, 0, 2, 0, 3, 2, ] 
current step: 1 
current vector in task: [3, 0, 2, 0, 3, 2, ] 
recV = [3, 1, 2, 1, 3, 2, ] 

爲什麼這個任務表現得如此奇怪?我能做些什麼來使它運行?

只是爲了完成後,代碼的其餘部分:

void printVector(vector<int> v) 
{ 
    cout << "["; 
    for (unsigned int var = 0; var < v.size(); ++var) { 
     cout << v[var] << ", "; 
    } 
    cout << "]" << endl; 
} 


void langford_parallel(int s, int n) 
{ 
    cout << "berechne Langenford-Sequenz für S = " << s << " und N = " << n << endl; 

// concurrent_vector<int> v((s*n), 0); 
    vector<int> v((s*n), 0); 

    int solutions = 0; 
    solutions = langford_task(n, v); 

    cout << "found solutions: " << solutions << endl; 
} 

int main() 
{ 
    tick_count t0 = tick_count::now(); 
// langford_sequentiell(2, 12); 
    langford_parallel(2, 3); 
    tick_count t1 = tick_count::now(); 

    cout << "work took " << (t1-t0).seconds() << " seconds." << endl; 
    return 0; 
} 

回答

1

有共享counter可以並行通過不同的任務在同一時間被修改經典data race

recV被引用超出範圍,因爲lambda函數通過引用引用它並在任務中異步執行。

如果你可以使用的lambda語法進行擴展,使得您可以在捕獲列表分配:在你的向量,以便通過價值指針傳遞

g.run([&, V{std::move(recV)}]{ counter += langford_task(step-1, V); }); 

否則,使用std::shared_ptr<>和防止載體超出範圍:

std::shared_ptr<std::vector<int>> recV (new std::vector<int>(v)); 
//... 
g.run([&, recV]{ counter += langford_task(step-1, *recV); }); 
+0

感謝您的回答。 我拿了櫃檯出來,我也沒有使用tbb :: atomic globalCounter; 這不會改變一個事實,即任務得到 [0,0,0,0,0,3]的 代替 [3,0,0,0,3,0,] 作爲參數。 我將我更改的文件上傳到 http://pastebin.com/xQtuVWpw – Rhiji

+0

謝謝你改進你的答案。我會很快嘗試一個 >(歡迎投票支持;) 對不起。我需要「15聲望」才能做到這一點,目前得到3分。我會記得一旦我贏得15個代表就回復你的答案。 – Rhiji

+0

這個:「」「std :: shared_ptr > recV = new std :: vector (v);」「」只是不編譯。在互聯網上沒有一個很好的使用例子,它描述瞭如何在一個向量中使用std :: shared_ptr <>。在這種情況下,g ++編譯器抱怨「轉換爲非標量類型」 – Rhiji

0

我對lambda函數發生了錯誤。

如上所述here,在我的情況下使用[=]是正確的λ-參數

g.run([=]{ counter += langford_task(step-1, recV); }); 

這使任務羣組任務的執行等的預期。

正如安東提到的,我還需要避免在櫃檯的競賽狀況。遲早我會面臨這個問題。

+0

好吧..這不正確從性能角度來看。你現在複製整個向量而不是移動分配,它是O(1)複雜度 – Anton

+0

我如何使它更有效率? – Rhiji