从c ++ dll到c#多次传递数据后,为什么我的程序停止?(没有错误信息) [英] Why does my program stop after passing data from c++ dll to c# several times? (There's no error message)

查看:60
本文介绍了从c ++ dll到c#多次传递数据后,为什么我的程序停止?(没有错误信息)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个项目,该项目需要dll文件才能使用c#编写的另一个程序使用(我对C ++/C#的用法不是很熟悉).在完成dll文件的开发之后,我开始了其测试过程(多次在C#中运行dll的函数调用以确保其正常工作).我已经问过将数据从C ++传递到C#的方法

我曾经说过,如果发生内存损坏,程序将在非常正常的行停止(例如std :: cout<< ...).我认为我的情况类似于那句话...

这是我的代码结构...

 <代码>//dll.hppextern"C" LIB_API无效推断(无符号字符* img_pointer,长data_len,cv :: Mat *& res,int& img_count,int& mat_type_size,双参数[2]);extern"C" LIB_API void clear_mem(cv :: Mat * res);//dll.cppLIB_API无效推断(无符号char * img_pointer,长data_len,cv :: Mat *& res,int& img_count,int& mat_type_size,双参数[2]){尝试{img_count = 8;mat_type_size = sizeof(cv :: Mat);res =新的cv :: Mat [img_count];cv :: Mat&img1 = res [0];cv :: Mat&img2 = res [1];cv :: Mat&img3 = res [2];cv :: Mat&img4 = res [3];cv :: Mat&img5 = res [4];cv :: Mat&img6 = res [5];cv :: Mat&img7 = res [6];cv :: Mat&img8 = res [7];//一些更新img1〜img8的过程std :: cout<<"res->"<<res<<std :: endl;std :: cout<<"=====完成推断过程=====>><<(std :: clock()-t_inf1)/(double)CLOCKS_PER_SEC<<"s"<<std :: endl;}捕获(const std :: runtime_error& re){std :: cerr<<"***运行时错误:"<<re.what()<<std :: endl;返回;}捕获(const std :: exception& ex){std :: cerr<<"***发生错误:"<<例如:what()<<std :: endl;返回;}抓住 (...){std :: cerr<<发生未知故障*** ...可能的内存损坏"<<std :: endl;返回;}}LIB_API void clear_mem(cv :: Mat * res){尝试{std :: cout<<>>在'clear_mem'中...."<<std :: endl;std :: cout<<"res in clear_mem->"<<res<<std :: endl;delete [] res;std :: cout<<>>完成删除res ...."<<std :: endl;}捕获(const std :: runtime_error& re){std :: cerr<<"***运行时错误:"<<re.what()<<std :: endl;返回;}捕获(const std :: exception& ex){std :: cerr<<"***发生错误:"<<例如:what()<<std :: endl;返回;}抓住 (...){std :: cerr<<发生未知故障*** ...可能的内存损坏"<<std :: endl;返回;}}//test.cs命名空间Test_Unet_Console{班级计划{[DllImport(@"D:\ Coco \ Code \ C_plus_plus \ unet_cpp_dll \ x64 \ Release \ unet_cpp_dll.dll"]]私有静态外部无效推断(byte [] img,long data_len,out IntPtr images,ref int img_count,out int mat_type_size,[In,MarshalAs(UnmanagedType.LPArray,SizeConst = 3)] double [] param);[DllImport(@"D:\ Coco \ Code \ C_plus_plus \ unet_cpp_dll \ x64 \ Release \ unet_cpp_dll.dll"]]私有静态外部无效init_inference();[DllImport(@"D:\ Coco \ Code \ C_plus_plus \ unet_cpp_dll \ x64 \ Release \ unet_cpp_dll.dll"]]私有静态外部无效clear_mem(IntPtr images);静态void Cppdll_inf(位图图像​​,out List< Mat> output_pic,double []参数,out IntPtr imgPtrs){Console.WriteLine("fmt之前");ImageFormat fmt =新的ImageFormat(image.RawFormat.Guid);Console.WriteLine("imageCodecInfo之前");var imageCodecInfo = ImageCodecInfo.GetImageEncoders().FirstOrDefault(codec => codec.FormatID == image.RawFormat.Guid);//这是针对未从磁盘读取图像并将其存储在内存中的情况(例如,图像来自相机或快照)如果(imageCodecInfo == null){fmt = ImageFormat.Jpeg;Console.WriteLine("C#-imageCodecInfo为null");}Console.WriteLine(之前的MemoryStream");使用(MemoryStream ms = new MemoryStream()){尝试{Console.WriteLine("C#-图像之前保存");image.Save(ms,fmt);Console.WriteLine("C#-完成图片.保存");byte [] image_byte_array = ms.ToArray();Console.WriteLine("C#-阅读完图片");int imgCount = 0;推断(image_byte_array,ms.Length,out var imgPtrs,ref imgCount,out var matTypeSize,param);output_pic =新的List< Mat>();为(int i = 0; i< imgCount; i ++){output_pic.Add(新Mat(IntPtr.Add(imgPtrs,i * matTypeSize)));}Console.WriteLine(完成从imgPtrs ....获得价值");}抓住(前例外){扔前}}}//我尝试将其添加到我的代码中,但这会导致一些错误(我没有记录...)静态void clear(){Console.WriteLine("start gc collect");GC.Collect();GC.WaitForPendingFinalizers();Console.WriteLine(完成gc清除收集");}静态无效的show_result(List< Mat> pic_list){为(int i = 0; i< pic_list.Count; i ++){Console.WriteLine(i);Cv2.ImShow("test",pic_list [i]);Cv2.WaitKey(500);}Cv2.DestroyAllWindows();Console.WriteLine(完成显示图片");}静态void Main(){位图image1 =新位图("C:\\ Users \\ Coco \\ Desktop \\(3).png");double [] param = {0.7,20};//{VI_threshold,area_threshold}Console.WriteLine(>>>从C#初始化========);init_inference();//>>模型初始化Console.WriteLine(>>>从C#完成初始化======");对于(int i = 0; i< 3; i ++){Console.WriteLine(i);List< Mat>结果;IntPtr imgPtrs;Cppdll_inf(image1,out result,param,out imgPtrs);复制代码//图片推断Console.WriteLine(>>>完成image1 C#======");show_result(结果);//显示图片以检查结果是否正确clear_mem(imgPtrs);//清理从dll发送的内存(?result.Clear();Console.WriteLine(>>>完成结果.Clear()======");Console.WriteLine("==============================);}}}} 

我尝试不将结果从dll返回到C#,它可以运行大约100次(我测试过的最大值).所以我认为问题可能出在将数据从dll传递到C#时的过程...

顺便说一下,这是我运行程序时的内存使用情况...

我已经在互联网上搜索了许多信息,但是我仍然不知道如何解决此问题,因此,非常感谢任何建议或帮助!

(感谢您阅读完我凌乱的问题描述!)

解决方案

很久以来,没有记录这个问题的答案...

有两种处理方式(以我的经验):

  1. 通过在cpp中执行 delete [] cv :: Mat * 添加功能,每次从dll收到 Mat * 后调用此函数>
  2. 在C#的DLL函数调用中使用 IDisposable类 li>

(想象一下,每次使用此语法运行后,它都会自行杀死)

(这是中文资料,但我认为它的内容很清楚示例代码)

I'm working on a project which required a dll file for another program written in c# to use (I'm not very familiar with the usage of C++/C#). After finishing the development(?) of the dll file, I started its testing process(run the function call from dll in C# for many times to ensure it works fine). I've asked the way to pass data from C++ to C# here, and the problem is, the program will stop without any error message(I've put try catch in my program) after calling it over 2 times.

I've seen a saying that if there's a memory corruption, the program will stop at a very normal line(e.g. std::cout << ...). I think my situation is similar to that saying...

And here's my code structure...

//dll.hpp
extern "C" LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat*& res, int& img_count, int& mat_type_size, double params[2]);
extern "C" LIB_API void clear_mem(cv::Mat* res);

//dll.cpp
LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat*& res, int& img_count, int& mat_type_size, double params[2])
{
    try
    {
        img_count = 8;
        mat_type_size = sizeof(cv::Mat);
        res = new cv::Mat[img_count];
        cv::Mat& img1 = res[0];
        cv::Mat& img2 = res[1];
        cv::Mat& img3 = res[2];
        cv::Mat& img4 = res[3];
        cv::Mat& img5 = res[4];
        cv::Mat& img6 = res[5];
        cv::Mat& img7 = res[6];
        cv::Mat& img8 = res[7];

        //some process to update img1~img8

        std::cout << "res->" << res << std::endl;
        std::cout << "===== finish inference process ===== >> " << (std::clock() - t_inf1) / (double)CLOCKS_PER_SEC << " s" << std::endl;

    }
    catch (const std::runtime_error& re)
    {
        std::cerr << "*** Runtime error: " << re.what() << std::endl;
        return;
    }
    catch (const std::exception& ex)
    {
        std::cerr << "*** Error occurred: " << ex.what() << std::endl;
        return;
    }
    catch (...)
    {
        std::cerr << "*** Unknown failure occurred... Possible memory corruption" << std::endl;
        return;
    }

}

LIB_API void clear_mem(cv::Mat* res)
{
    try
    {
        std::cout << ">> In 'clear_mem'...." << std::endl;
        std::cout << "res in clear_mem->" << res << std::endl;
        delete[] res;
        std::cout << ">> finish deleting res...." << std::endl;
    }
    catch (const std::runtime_error& re)
    {
        std::cerr << "*** Runtime error: " << re.what() << std::endl;
        return;
    }
    catch (const std::exception& ex)
    {
        std::cerr << "*** Error occurred: " << ex.what() << std::endl;
        return;
    }
    catch (...)
    {
        std::cerr << "*** Unknown failure occurred... Possible memory corruption" << std::endl;
        return;
    }
}

//test.cs
namespace Test_Unet_Console
{
    class Program
    {
        [DllImport(@"D:\Coco\Code\C_plus_plus\unet_cpp_dll\x64\Release\unet_cpp_dll.dll")]
        private static extern void inference(byte[] img, long data_len, out IntPtr images, ref int img_count, out int mat_type_size,
                                            [In, MarshalAs(UnmanagedType.LPArray, SizeConst = 3)]double[] param);
        [DllImport(@"D:\Coco\Code\C_plus_plus\unet_cpp_dll\x64\Release\unet_cpp_dll.dll")]
        private static extern void init_inference();

        [DllImport(@"D:\Coco\Code\C_plus_plus\unet_cpp_dll\x64\Release\unet_cpp_dll.dll")]
        private static extern void clear_mem(IntPtr images);

        static void Cppdll_inf(Bitmap image, out List<Mat> output_pic, double[] param, out IntPtr imgPtrs)
        {
            Console.WriteLine("before fmt");
            ImageFormat fmt = new ImageFormat(image.RawFormat.Guid);
            Console.WriteLine("before imageCodecInfo");
            var imageCodecInfo = ImageCodecInfo.GetImageEncoders().FirstOrDefault(codec => codec.FormatID == image.RawFormat.Guid);
            //this is for situations, where the image is not read from disk, and is stored in the memory(e.g. image comes from a camera or snapshot)
            if (imageCodecInfo == null)
            {
                fmt = ImageFormat.Jpeg;
                Console.WriteLine("C# - imageCodecInfo is null");
            }
            Console.WriteLine("before MemoryStream");
            using (MemoryStream ms = new MemoryStream())
            {
                try
                {
                    Console.WriteLine("C# - before image.Save");
                    image.Save(ms, fmt);
                    Console.WriteLine("C# - finish image.Save");
                    byte[] image_byte_array = ms.ToArray();
                    Console.WriteLine("C# - finish reading pic");

                    int imgCount = 0;

                    inference(image_byte_array, ms.Length, out var imgPtrs, ref imgCount, out var matTypeSize, param);
                    output_pic = new List<Mat>();
                    for (int i = 0; i < imgCount; i++)
                    {
                        output_pic.Add(new Mat(IntPtr.Add(imgPtrs, i * matTypeSize)));
                    }
                    Console.WriteLine("finish getting value from imgPtrs.....");

                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        // I've tried to add this in my code, but it will cause some error(I didn't record it...)
        static void clear() 
        {

            Console.WriteLine("start gc collect");
            GC.Collect();
            GC.WaitForPendingFinalizers();
            Console.WriteLine("finish gc collect in clear");
        }

        static void show_result(List<Mat> pic_list)
        {
            for (int i = 0; i < pic_list.Count; i++)
            {
                Console.WriteLine(i);
                Cv2.ImShow("test", pic_list[i]);
                Cv2.WaitKey(500);
            }
            Cv2.DestroyAllWindows();
            Console.WriteLine("finish showing pic");
        }


        static void Main()
        {
            Bitmap image1 = new Bitmap("C:\\Users\\Coco\\Desktop\\(3).png");
            double[] param = { 0.7, 20 }; //{ VI_threshold, area_threshold }
            Console.WriteLine(">>> Initializing from C# =======");
            init_inference(); // >> initialization of models
            Console.WriteLine(">>> Finish initializing from C# ======");

            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine(i);
                List<Mat> result;
                IntPtr imgPtrs;
                Cppdll_inf(image1, out result, param, out imgPtrs); // inference of picture
                Console.WriteLine(">>> Finish image1 C# ======");
                show_result(result); // showing pic to check if result is correct
                clear_mem(imgPtrs); //  clean the memory send from dll(?
                result.Clear(); 
                Console.WriteLine(">>> Finish result.Clear() ======");
                Console.WriteLine("================================");
            }
        }
    }
}

I've tried not to return the result from dll to C#, it can run about 100 times(the maximum I've tested). So I think the problem might be the process when passing data from dll to C#...

By the way, here's my memory usage when running the program...

I've searched many info on the internet, but I still have no idea how to fix this problem, so any advise or help is really appreciated!

(Thanks in advance for finish reading my messy question description! )

解决方案

It's been quite long not recording the answer of this question...

There are two ways to handle this(in my experience):

  1. Adding a function with doing delete[] cv::Mat* in your cpp, call this function every time after you received a Mat* from dll
  2. Using IDisposable Class in C#'s calling with DLL function

(Imagine like it kills itself after every run with this syntax)

(This is Chinese material, but I think it's pretty clear with its example code)

这篇关于从c ++ dll到c#多次传递数据后,为什么我的程序停止?(没有错误信息)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆