我正在开发一个项目,该项目需要一个 dll 文件供另一个用 c# 编写的程序使用。由于我不是很熟悉 C++ 和 C# 从 dll 调用函数的细节...
FIRST - 我以最基本的方式编写了我需要的那些函数
->由A.h、A.cpp组成,用VS2015构建的文件A.exe运行
第二 - 我将上面成功运行的代码修改为可以通过dll文件从c#调用一些函数的格式
->由A.h、A.cpp组成,得到一个从VS2015构建的A.dll
第三 - 我通过一个简单的C#程序测试dll文件的功能
由于代码要用在实时推理上(使用tensorflow的模型),所以我把模型初始化部分写在一个函数里,推理部分写在另一个函数里。我把模型的所有功能都变成了一个类(包括initialize 和inference)。
我在项目中使用了不止1个模型,模型在初始化后不会被修改。由于它们必须在不同的功能中使用,我决定将每个类(模型)全局化。
//file.h
class UnetInterface
{
public:
UnetInterface(std::string model_path);
int predict(cv::Mat srcImage, cv::Mat& dstimage);
private:
....
};
//file.cpp
//I put those class declaration outside functions to make them globally
UnetInterface A = UnetInterface(path1);
UnetInterface B = UnetInterface(path2);
UnetInterface::UnetInterface(string model_path)
{
inp_tensor_name = "input_1:0";
out_tensor_name = "conv2d_19/Sigmoid:0";
std::cout << "UnetInerface-> " << model_path << std::endl;
Status status_load = ReadBinaryProto(Env::Default(), model_path, &graphdef);
std::cout << ">>> initial model in InetInterface" << std::endl;
if (!status_load.ok()) {
std::cout << "ERROR: Loading model failed..." << std::endl;
std::cout << model_path << status_load.ToString() << "\n";
}
NewSession(SessionOptions(), &session); //looks like it always stuck in here while initializing
Status status_create = session->Create(graphdef);
if (!status_create.ok()) {
std::cout << "ERROR: Creating graph in session failed.." << status_create.ToString() << std::endl;
}
else {
std::cout << "----------- Successfully created session and load graph -------------" << std::endl;
}
}
// initialization of those class objects
// this can speed up the speed of inference afterwards
void init()
{
A.predict(pic_1);
B.predict(pic_2);
}
LIB_API void inference(pic) // the function c# calling for each inference
{
A.predict(pic_x);
B.predict(pic_y);
}
上面的声明在我上面提到的第一种方式中工作正常...... https://i.imgur.com/P4xngTj.png
但如果它在 c# 中运行(如下所示的 exe 文件),它总是在初始化时卡住。 https://i.imgur.com/Ts5ZaeK.png
我也试过在.h文件中声明类的方式,在.cpp文件中调用它们,结果和上面的方法一样。
// file.hpp
extern UnetInterface A = UnetInterface(path1);
extern UnetInterface A = UnetInterface(path2);
所以我想出了另外一种方法,初始化后返回一个class的struct。 但是,我不太确定创建类结构的正确方法是什么,这是我到目前为止所做的(有一些错误我写为评论):
//file.h
struct Unets // The struct that stores initialized classes
{
UnetInterface A;
UnetInterface B;
};
//file.cpp
Unets init() // initialization of those class objects
{
Unets TT; // error: 'Unets::Unets(void)':attempting to reference a deleted function
// error: the default constructor of "Unets" cannot be referenced -- it is a deleted function
TT.A = UnetInterface(path1);
TT.A.predict(pic1);
TT.B = UnetInterface(path2);
TT.B.predict(pic2);
...
...
return TT;
}
LIB_API void inference(pic3) // the function c# calling for each inference
{
Unets TT2; // error: the default constructor of "Unets" cannot be referenced -- it is a deleted function
TT2 = init();
TT2.predict(pic3);
}
我不知道是否有必要为每次使用函数“推理”重新声明结构“Unets”。如果是,我认为这样写不是一个好主意,所以我被困在这里......
总而言之,我想知道...
<强>1。为什么我声明为 FIRST 方式的全局类在 C# 中运行时失败?
<强>2。最后一种方法是可行的选择吗?如果是/不是,关于返回多个初始化类(模型)的任何其他建议?
(提前感谢您阅读我凌乱的问题描述...
感谢任何建议或帮助 :D )
最佳答案
首先,您需要在此处分离您的问题,因为我看到有两个项目。首先,关于使用全局静态初始化从 Dll 运行代码。其次,关于使用 TensorFlow 推理结构运行代码。
关于第一项,这应该有效。您可以通过使用简单任务(例如,控制台打印输出)而不是 tensorflow 初始化(将它们注释掉)来运行它们来尝试这些。第二项,在您的情况下,可能是第一个 exe 占用了 GPU,因此,第二个 exe 正在等待。
更新
一些代码建议:
//file.cpp
#include <memory>
std::shared_ptr<Unets> init() // initialization of those class objects
{
//Unets TT; // error: 'Unets::Unets(void)':attempting to reference a deleted function
// error: the default constructor of "Unets" cannot be referenced -- it is a deleted function
auto TT = std::make_shared<Unets>();
...
...
return TT;
}
LIB_API void inference(pic3) // the function c# calling for each inference
{
//Unets TT2; // error: the default constructor of "Unets" cannot be referenced -- it is a deleted function
auto TT2 = init();
TT2->A.predict(pic3);
}
关于c# - 为什么它无法在构建为 dll 文件的 c++ 中全局声明一个类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58202051/