螺纹构建块(TBB)```enqueue```任务生命周期

时间:2014-03-13 19:35:20

标签: c++ multithreading c++11 concurrency tbb

如果在函数中使用tbb::task::enqueue将任务排入队列,然后在执行任务之前函数超出范围,那么任务是否会丢失?

如果是这样,怎么可以避免?例如,如果您想要在短期事件处理程序回调中将任务排入队列,这将很快超出范围,而调度程序将在稍后执行该任务?

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

1 个答案:

答案 0 :(得分:2)

tbb::task是一个对象。相同的C ++生存期规则(和危险!)适用于tbb::task和任何其他C ++对象。对于相关案例,请务必以不会受返回函数影响的方式捕获任务中的信息。例如,捕获局部变量的值,而不是引用。

这是一个使用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);
    }
}

如果你运行它,你会看到&#34;启动......&#34;行正确打印ij,但是&#34; Hi来自...&#34;行打印j错误值。这是因为lambda已经通过引用(j)捕获了&j,并且引用了一个在任务运行之前消失的左值。

据我所知,tbb::task::enqueue的容量限制是系统内存的容量限制。它取决于程序员,以确保不会发生这种情况。