我尝试了解intel tbb中的任务。我尝试创建一个并行算法来解决langfords削减两个"块" L(2,n)的(https://en.wikipedia.org/wiki/Langford_pairing)
当我调用顺序时,我的算法有效,但我想在任务中翻译它。这就是我的算法应该做的事情:
我目前忽略对称性
这是当前的代码
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;
}
答案 0 :(得分:1)
共享counter
上有经典的first parent,可以同时由不同的任务并行修改。
并且recV
被引用超出范围,因为lambda函数通过引用获取它并在任务中异步执行。
如果您可以使用data race,则会扩展lambda语法,以便您可以在捕获列表中进行分配:
g.run( [&, V{std::move(recV)}]{ counter += langford_task( step-1, V); } );
否则,c++14在向量周围使用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); } );
这使得任务组的执行工作与预期的一样。
正如安东所说,我还需要避开柜台的竞争条件。我迟早会遇到这个问题。