Destroying a runtime before destroying deserialized engines created by the runtime leads to undefine

完整报错:[E] [TRT] 3: [runtime.cpp::nvinfer1::Runtime::~Runtime::346] Error Code 3: API Usage Error (Parameter check failed at: runtime.cpp::nvinfer1::Runtime::~Runtime::346, condition: mEngineCounter.use_count() == 1. Destroying a runtime before destroying deserialized engines created by the runtime leads to undefined behavior.
)

我在使用TensorRT推理的时候,出现了这个错误。

首先,tensorRT推理的构建顺序是:

  1. 创建推理运行时runtime

  2. 反序列化生成engine

  3. 创建执行上下文context

这个顺序是固定的,后序受前序影响。

若这三个函数在一个函数里面那么不会出现上述错误,例如下面的代码:

    // 1
    auto runtime = std::unique_ptr<nvinfer1::IRuntime>(nvinfer1::createInferRuntime(sample::gLogger.getTRTLogger()));
    if (!runtime)
    {
        std::cout << "runtime create failed" << std::endl;
        return -1;
    }
    

    //2
    // 加载模型文件
    auto plan = load_engine_file(engine_file);
    // 反序列化生成engine
    auto mEngine = std::shared_ptr<nvinfer1::ICudaEngine>(runtime->deserializeCudaEngine(plan.data(), plan.size()));
    if (!mEngine)
    {
        return -1;
    }

    // 3
    auto context = std::unique_ptr<nvinfer1::IExecutionContext>(mEngine->createExecutionContext());
    if (!context)
    {
        std::cout << "context create failed" << std::endl;
        return -1;
    }

但如果,把这个函数式的流程修改为类的形式就会报错:

class Tensor {
public:
    std::shared_ptr<nvinfer1::ICudaEngine> mEngine;
    std::unique_ptr<nvinfer1::IRuntime> runtime;
    std::unique_ptr<nvinfer1::IExecutionContext> context;
    samplesCommon::BufferManager* buffers;
    Tensor();
    ~Tensor();
public:
    bool init();
};

 在init中执行初始化。

这样看是没有什么问题的,但在程序结束时就会上面的错误,翻译:在销毁运行时创建的反序列化引擎之前销毁运行时会导致未定义的行为。

就是说:runtime应该在mEngine后销毁。

这里就存在一个成员变量之间的构造与析构顺序的问题了,可以查看下面的代码:

#include <iostream>
// 成员类
class A{
public:
    A(){
        std::cout<< "A" <<std::endl;
    }
    ~A(){
        std::cout<< "~A" <<std::endl;
    }
};
class B{
public:
    B(){
        std::cout<< "B" <<std::endl;
    }
    ~B(){
        std::cout<< "~B" <<std::endl;
    }
};
// 父类
class C{
public:
    C(){
        std::cout<< "C" <<std::endl;
    }
    ~C(){
        std::cout<< "~C" <<std::endl;
    }
};

// 子类
class D : public  C{
public:
    D(){
        std::cout<< "D" <<std::endl;
    }
    ~D(){
        std::cout<< "~D" <<std::endl;
    }
public:
    A a;
    B b;
};

int main(int argc, char **argv){
    D d;
}

结果:

/*

C 父
A 先声明的成员
B 后声明的成员
D 子

~D 子
~B 后声明的成员
~A 先声明的成员
~C 父

*/

就是说我们的runtime要先声明,而mEngine要后声明,才能达到后声明的先析构,先声明的后析构的目的,所以runtime要放在mEngine前面。

class Tensor {
public:
    std::unique_ptr<nvinfer1::IRuntime> runtime;
    std::shared_ptr<nvinfer1::ICudaEngine> mEngine;
    std::unique_ptr<nvinfer1::IExecutionContext> context;
    samplesCommon::BufferManager* buffers;
    Tensor();
    ~Tensor();
public:
    bool init();
};

当然context也必须在mEngine后面,否则会报类似的顺序报错。

这里你无法通过析构函数通过手动的方式去释放智能指针代理的对象(有没有这样的接口,我还暂时没有了解过,因为智能指针存在的目的就是去代理释放,而非手动),所以只能通过修改声明顺序的方式来修改,以解决这个问题。

 问题来源:推理报错

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值