2015-11-26 8 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