如果使用tbb::task::enqueue
在函数中排队一个任务,然后在功能超出执行任务之前范围,将任务迷路?线程构建模块(TBB)```enqueue```任务寿命
如果是这样,那怎么可以避免?例如,如果你想在一个短暂的事件处理程序回调中加入一个任务,这个回调将很快超出范围,而这个任务将不会被调度器执行,直到稍后呢?
此外,请问enqueue
功能有容量限制?如果有超过一定数量的待处理任务,它是否会放弃任务?
如果使用tbb::task::enqueue
在函数中排队一个任务,然后在功能超出执行任务之前范围,将任务迷路?线程构建模块(TBB)```enqueue```任务寿命
如果是这样,那怎么可以避免?例如,如果你想在一个短暂的事件处理程序回调中加入一个任务,这个回调将很快超出范围,而这个任务将不会被调度器执行,直到稍后呢?
此外,请问enqueue
功能有容量限制?如果有超过一定数量的待处理任务,它是否会放弃任务?
甲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);
}
}
如果你运行它,你会看到“发射......”行打印i
和j
正确,但“喜从...”行打印错误值为j
。这是因为lambda已经通过引用(&j
)捕获了j
,并且引用是在任务运行之前消失的左值。
据我所知,tbb::task::enqueue
容量极限是系统内存的容量限制。程序员要确保这不会发生。