tbb-tasks不接收给定的参数

时间:2015-11-26 11:04:03

标签: c++ task intel tbb

我尝试了解intel tbb中的任务。我尝试创建一个并行算法来解决langfords削减两个"块" L(2,n)的(https://en.wikipedia.org/wiki/Langford_pairing

当我调用顺序时,我的算法有效,但我想在任务中翻译它。这就是我的算法应该做的事情:

  • 制作一个大小为2 * n的向量,使用" 0"
  • 进行初始化
  • 表示0直到(1 + loopcounter + block-of-blocks)<矢量的大小:
  • 复制给定的载体
  • 在loopcounter上添加当前块
  • 在1 + loopcounter + distance-of-blocks
  • 上添加当前块
  • 如果这不是最后一个块:
  • 在具有块差-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应该在foor-loop结束时等待,所以所有的子任务都可以先完成。

我打印了矢量,所以我可以看到里面的东西,这有点奇怪:

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
这是绝对奇怪的。我必须提到&#34; 28848976&#34;似乎是一个随机数。它总是不同的,大部分时间都是&#34; 0&#34;

我期待&#34;任务中的当前向量:&#34;在&#34;当前步骤:2&#34; -section

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

因为这只是我给这个函数的参数。

它&#34;工作&#34;当我添加     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;
}

2 个答案:

答案 0 :(得分:1)

共享counter上有经典的first parent,可以同时由不同的任务并行修改。

并且recV被引用超出范围,因为lambda函数通过引用获取它并在任务中异步执行。

如果您可以使用data race,则会扩展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); } );

答案 1 :(得分:0)

我在lambda函数中犯了一个错误。

正如here所述,在我的用例[=]中是正确的Lambda参数

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

这使得任务组的执行工作与预期的一样。

正如安东所说,我还需要避开柜台的竞争条件。我迟早会遇到这个问题。