【问题标题】:Threaded Building Blocks (TBB) ```enqueue``` task lifetime线程构建块 (TBB) ```入队``` 任务生命周期
【发布时间】:2014-03-13 19:35:19
【问题描述】:

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

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

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

【问题讨论】:

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


    【解决方案1】:

    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);
        }
    }
    

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多