2014-03-13 34 views
1

如果使用tbb::task::enqueue在函数中排队一个任务,然后在功能超出执行任务之前范围,将任务迷路?线程构建模块(TBB)```enqueue```任务寿命

如果是这样,那怎么可以避免?例如,如果你想在一个短暂的事件处理程序回调中加入一个任务,这个回调将很快超出范围,而这个任务将不会被调度器执行,直到稍后呢?

此外,请问enqueue功能有容量限制?如果有超过一定数量的待处理任务,它是否会放弃任务?

回答

2

tbb::task是一个对象。与其他C++对象相同,C++生命周期规则(和危险!)适用于tbb::task。对于有问题的情况,确保以不受返回函数影响的方式捕获任务中的信息。例如,捕获本地变量的值,而不是引用。

这是一个使用lambda表达式显示问题的程序。它借用Alexey Kukanov's lambda_task

#include <tbb/tbb.h> 

template<typename F> 
class lambda_task : public tbb::task { 
    F my_func; 
    /*override*/ tbb::task* execute() { 
     my_func(); 
     return NULL; 
    } 
public: 
    lambda_task(const F& f) : my_func(f) {} 
}; 

template<typename F> 
void tbb_enqueue_lambda(const F& f) { 
    tbb::task::enqueue(*new(tbb::task::allocate_root()) lambda_task<F>(f)); 
} 

void LaunchOneTask(int i, int j) { 
    if(i%1000000==0) 
     [i,&j]{printf("Launching i=%d j=%d\n",i,j);}(); 
    tbb_enqueue_lambda([i,&j]{      // Deliberate mistake for j! 
     printf("Hi from lambda: i=%d j=%d\n",i,j); 
     sleep(1); 
    }); 
} 

int main() { 
    for(int i=0; i<1000000000; ++i) { 
     LaunchOneTask(i,i); 
    } 
} 

如果你运行它,你会看到“发射......”行打印ij正确,但“喜从...”行打印错误值为j。这是因为lambda已经通过引用(&j)捕获了j,并且引用是在任务运行之前消失的左值。

据我所知,tbb::task::enqueue容量极限是系统内存的容量限制。程序员要确保这不会发生。