线程构建块(TBB)' ' enqueue ' ' ' '任务生存期
Threaded Building Blocks (TBB) ```enqueue``` task lifetime
如果在函数中使用tbb::task::enqueue
来为任务排队,然后在任务执行之前该函数超出了作用域,任务会丢失吗?
如果是这样,如何避免呢?例如,如果您希望在短期事件处理程序回调中为任务排队,该任务将很快超出范围,而调度程序直到稍后才执行该任务,该怎么办?
此外,enqueue
函数是否有容量限制?如果有超过一定数量的待处理任务,它会丢弃任务吗?
tbb::task
为对象。与任何其他c++对象一样,同样的c++生命周期规则(和危险!)也适用于tbb::task
。对于所讨论的情况,请确保以不受返回函数影响的方式捕获任务中的信息。例如,捕获局部变量的值,而不是引用。
下面的程序使用lambda表达式显示了这个问题。它借用了Alexey Kukanov的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=%dn",i,j);}();
tbb_enqueue_lambda( [i,&j]{ // Deliberate mistake for j!
printf("Hi from lambda: i=%d j=%dn",i,j);
sleep(1);
} );
}
int main() {
for( int i=0; i<1000000000; ++i ) {
LaunchOneTask(i,i);
}
}
如果运行它,您将看到"Launching…"行正确地打印了i
和j
,但是"Hi from…"行打印了j
的错误的值。这是因为lambda通过引用(&j
)捕获了j
,并且该引用指向一个在任务运行之前消失的左值。
据我所知,tbb::task::enqueue
上的容量限制是系统内存的容量限制。这取决于程序员确保不会发生这种情况。
相关文章:
- GCC对可能有效的代码抛出init list生存期警告
- 在不复制临时对象的情况下延长其生存期
- 结束另一个线程中使用的对象的生存期
- "this"指针的值在对象的生存期内是否恒定?
- 创建具有全局生存期的 UObject
- C++17 和静态临时生存期的参考扩展
- 数组对象的生存期是否在重用其元素存储时结束?
- 共享指针生存期
- 具有空洞初始化的对象的生存期
- 如何在向量列表初始化时避免对象复制以及如何延长临时的生存期
- 指针引用的生存期(以 C++为单位)
- 子表达式中临时对象的生存期
- 对临时对象的Const引用不会延长其生存期
- 对象存在与对象生存期不同吗
- 指向对象生存期之外的已分配内存的指针是"invalid pointer[s]"还是"pointer[s] to an object"?
- 全局静态生存期?他们会让你的程序崩溃吗?
- "std::function"的简单版本:函数对象的生存期?
- 您能否根据是否使用返回值来保证不同的生存期行为?
- 理解C++指针生存期/僵尸指针
- 线程构建块(TBB)' ' enqueue ' ' ' '任务生存期